svn merge -r 16593:16648 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender-staging.git] / source / blender / src / editipo.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2005. Full recode.
24  * Roland Hess, 2007. Visual Key refactor.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29
30 /* this code feels over-complex, mostly because I choose in the past to devise a system
31   that converts the Ipo blocks (linked to Object, Material, etc), into a copy of that
32   data which is being worked on;  the 'editipo'.
33   The editipo then can have 'ipokey' data, which is optimized for editing curves as if
34   it were key positions. This is still a great feature to work with, which makes ipo editing
35   in Blender still valuable. However, getting this beast under control was hard, even
36   for me... (ton) */
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h>
41
42 #ifndef WIN32
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #endif   
47 #include "MEM_guardedalloc.h"
48 #include "PIL_time.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52
53 #include "DNA_constraint_types.h"
54 #include "DNA_action_types.h"
55 #include "DNA_armature_types.h"
56 #include "DNA_camera_types.h"
57 #include "DNA_curve_types.h"
58 #include "DNA_group_types.h"
59 #include "DNA_ipo_types.h"
60 #include "DNA_key_types.h"
61 #include "DNA_lamp_types.h"
62 #include "DNA_material_types.h"
63 #include "DNA_modifier_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_object_fluidsim.h"
66 #include "DNA_particle_types.h"
67 #include "DNA_screen_types.h"
68 #include "DNA_scene_types.h"
69 #include "DNA_space_types.h"
70 #include "DNA_sequence_types.h"
71 #include "DNA_sound_types.h"
72 #include "DNA_texture_types.h"
73 #include "DNA_userdef_types.h"
74 #include "DNA_view3d_types.h"
75 #include "DNA_world_types.h"
76
77 #include "BKE_action.h"
78 #include "BKE_armature.h"
79 #include "BKE_anim.h"
80 #include "BKE_constraint.h"
81 #include "BKE_depsgraph.h"
82 #include "BKE_global.h"
83 #include "BKE_group.h"
84 #include "BKE_ipo.h"
85 #include "BKE_key.h"
86 #include "BKE_main.h"
87 #include "BKE_material.h"
88 #include "BKE_modifier.h"
89 #include "BKE_particle.h"
90 #include "BKE_texture.h"
91 #include "BKE_utildefines.h"
92 #include "BKE_object.h"
93
94 #include "BIF_butspace.h"
95 #include "BIF_editaction.h"
96 #include "BIF_editconstraint.h"
97 #include "BIF_editkey.h"
98 #include "BIF_editnla.h"
99 #include "BIF_editseq.h"
100 #include "BIF_editview.h"
101 #include "BIF_interface.h"
102 #include "BIF_keyframing.h"
103 #include "BIF_mywindow.h"
104 #include "BIF_poseobject.h"
105 #include "BIF_screen.h"
106 #include "BIF_space.h"
107 #include "BIF_toolbox.h"
108 #include "BIF_poseobject.h"
109
110 #include "BDR_drawobject.h"
111 #include "BDR_editobject.h"
112 #include "BDR_editcurve.h"      // for bezt_compare 
113
114 #include "BSE_trans_types.h"
115 #include "BSE_editipo_types.h"
116 #include "BSE_drawipo.h"
117 #include "BSE_editipo.h"
118 #include "BSE_edit.h"
119 #include "BSE_drawview.h"
120 #include "BSE_headerbuttons.h"
121 #include "BSE_node.h"
122 #include "BSE_sequence.h"
123 #include "BSE_seqaudio.h"
124 #include "BSE_time.h"
125
126 #include "blendef.h"
127 #include "mydevice.h"
128 #include "transform.h"
129
130 extern int ob_ar[];
131 extern int ma_ar[];
132 extern int seq_ar[];
133 extern int cu_ar[];
134 extern int wo_ar[];
135 extern int la_ar[];
136 extern int cam_ar[];
137 extern int snd_ar[];
138 extern int ac_ar[];
139 extern int co_ar[];
140 extern int te_ar[];
141 extern int fluidsim_ar[]; // NT
142 extern int part_ar[];
143
144 /* forwards */
145 #define IPOTHRESH       0.9
146
147 /* tests if only one editipo is active */
148 static void check_active_editipo(void)
149 {
150         EditIpo *ei, *actei;
151         int a;
152         
153         actei= G.sipo->editipo;
154         if(actei) {
155                 for(a=0; a<G.sipo->totipo; a++, actei++) {
156                         if(actei->flag & IPO_ACTIVE) 
157                                 break;
158                 }
159                 if(actei==NULL) {
160                         /* set visible active */
161                         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
162                                 if(ei->flag & IPO_VISIBLE)
163                                         break;
164                         }
165                         if(ei==NULL) ei=G.sipo->editipo;
166                         ei->flag |= IPO_ACTIVE;
167                         if(ei->icu) ei->icu->flag |= IPO_ACTIVE;
168                 }
169                 else {
170                         /* make sure no others are active */
171                         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
172                                 if(ei!=actei) {
173                                         ei->flag &= ~IPO_ACTIVE;
174                                         if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
175                                 }
176                         }
177                 }
178         }
179 }
180
181 /* sets this ei channel active */
182 static void set_active_editipo(EditIpo *actei)
183 {
184         EditIpo *ei;
185         int a;
186         
187         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
188                 ei->flag &= ~IPO_ACTIVE;
189                 if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
190         }
191         actei->flag |= IPO_ACTIVE;
192         if(actei->icu) actei->icu->flag |= IPO_ACTIVE;
193 }
194
195 EditIpo *get_active_editipo(void)
196 {
197         EditIpo *ei;
198         int a;
199         
200         if(G.sipo==NULL)
201                 return NULL;
202         
203         /* prevent confusing situations, like for sequencer */
204         if(G.sipo->totipo==1) {
205                 ei= G.sipo->editipo;
206                 ei->flag |= IPO_ACTIVE;
207                 return ei;
208         }
209         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++)
210                 if(ei->flag & IPO_ACTIVE)
211                         return ei;
212         
213         return NULL;
214 }
215
216 static void set_active_key(int index)
217 {
218         if(G.sipo->blocktype==ID_KE && G.sipo->from) {
219                 Object *ob= (Object *)G.sipo->from;
220                 Key *key= ob_get_key(ob);
221                 
222                 if(key) {
223                         KeyBlock *curkb;
224                         
225                         curkb= BLI_findlink(&key->block, index-1);
226                         if(curkb) {
227                                 ob->shapenr= index;
228                                 ob->shapeflag |= OB_SHAPE_TEMPLOCK;
229                                 
230                                 /* calc keypos */
231                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
232                                 allqueue(REDRAWVIEW3D, 0);
233                                 allqueue(REDRAWBUTSEDIT, 0);
234                         }
235                 }
236         }                       
237 }
238
239 void editipo_changed(SpaceIpo *si, int doredraw)
240 {
241         EditIpo *ei;
242         View2D *v2d;
243         Key *key;
244         KeyBlock *kb;
245         int a, first=1;
246
247         ei= si->editipo;
248         if(ei==0)
249                 return;
250         
251         for(a=0; a<si->totipo; a++, ei++) {
252                 
253                 if(ei->icu) {
254                         
255                                 /* twice because of ittererating new autohandle */
256                         calchandles_ipocurve(ei->icu);
257                         calchandles_ipocurve(ei->icu);
258                         
259                         if(ei->flag & IPO_VISIBLE) {
260                 
261                                 boundbox_ipocurve(ei->icu, 0);
262                                 sort_time_ipocurve(ei->icu);
263                                 if(first) {
264                                         si->v2d.tot= ei->icu->totrct;
265                                         first= 0;
266                                 }
267                                 else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
268                         }
269                 }
270         }
271         
272
273         v2d= &(si->v2d);        
274
275         /* keylines? */
276         if(si->blocktype==ID_KE) {
277                 key= ob_get_key((Object *)G.sipo->from);
278                 if(key && key->block.first) {
279                         kb= key->block.first;
280                         if(kb->pos < v2d->tot.ymin) v2d->tot.ymin= kb->pos;
281                         kb= key->block.last;
282                         if(kb->pos > v2d->tot.ymax) v2d->tot.ymax= kb->pos;
283                 }
284         }
285         
286         /* is there no curve? */
287         if(first) {
288                 v2d->tot.xmin= 0.0;
289                 v2d->tot.xmax= EFRA;
290                 v2d->tot.ymin= (float)-0.1;
291                 v2d->tot.ymax= (float)1.1;
292         
293                 if(si->blocktype==ID_SEQ) {
294                         v2d->tot.xmin= -5.0;
295                         v2d->tot.xmax= 105.0;
296                         v2d->tot.ymin= (float)-0.1;
297                         v2d->tot.ymax= (float)1.1;
298                 }
299         }
300         
301         si->tot= v2d->tot;      
302         
303         if(doredraw) {
304                 /* if you always call do_ipo: you get problems with insertkey, for example
305                  * when inserting only a 'loc' the 'ob->rot' value then is changed.
306                  */
307
308                 if(si->blocktype==ID_OB) {                      
309                                 /* clear delta loc,rot,size (when free/delete ipo) */
310                         clear_delta_obipo(si->ipo);
311                         
312                 }
313         
314                 do_ipo(si->ipo);
315
316                 allqueue(REDRAWIPO, 0);
317                 allqueue(REDRAWACTION, 0);
318                 allqueue(REDRAWTIME, 0);
319                 allqueue(REDRAWNLA, 0);
320                 allqueue(REDRAWBUTSOBJECT, 0);
321                 
322                 if(si->blocktype==ID_OB) {
323                         Object *ob= (Object *)si->from;                 
324                         if(ob) DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
325                         allqueue(REDRAWVIEW3D, 0);
326                         allqueue(REDRAWNLA, 0);
327                 }
328
329                 else if(si->blocktype==ID_MA) allqueue(REDRAWBUTSSHADING, 0);
330                 else if(si->blocktype==ID_TE) allqueue(REDRAWBUTSSHADING, 0);
331                 else if(si->blocktype==ID_WO) allqueue(REDRAWBUTSSHADING, 0);
332                 else if(si->blocktype==ID_LA) allqueue(REDRAWBUTSSHADING, 0);
333 //              else if(si->blocktype==ID_SO) allqueue(REDRAWBUTSSOUND, 0);
334                 else if(si->blocktype==ID_CA) {
335                         allqueue(REDRAWBUTSEDIT, 0);
336                         allqueue(REDRAWVIEW3D, 0);
337                 }
338                 else if(si->blocktype==ID_SEQ) free_imbuf_seq_with_ipo(si->ipo);
339                 else if(si->blocktype==ID_PO) {
340                         Object *ob= OBACT;
341                         if(ob && ob->pose) {
342                                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
343                         }
344                         allqueue(REDRAWVIEW3D, 0);
345                         allqueue(REDRAWACTION, 0);
346                         allqueue(REDRAWNLA, 0);
347                 }
348                 else if(si->blocktype==ID_KE) {
349                         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
350                         allqueue(REDRAWVIEW3D, 0);
351                 }
352                 else if(si->blocktype==ID_CU) {
353                         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
354                         allqueue(REDRAWVIEW3D, 0);
355                 }
356                 else if(si->blocktype==ID_PA){
357                         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
358                         allqueue(REDRAWVIEW3D, 0);
359                 }
360         }
361
362         if(si->showkey) make_ipokey();
363         
364         if(si->actname[0])
365                 synchronize_action_strips();
366 }
367
368 void scale_editipo(void)
369 {
370         /* comes from buttons, scale with G.sipo->tot rect */
371         
372         EditIpo *ei;
373         BezTriple *bezt;
374         float facx, facy;
375         int a, b;       
376         
377         facx= (G.sipo->tot.xmax-G.sipo->tot.xmin)/(G.sipo->v2d.tot.xmax-G.sipo->v2d.tot.xmin);
378         facy= (G.sipo->tot.ymax-G.sipo->tot.ymin)/(G.sipo->v2d.tot.ymax-G.sipo->v2d.tot.ymin);
379
380         ei= G.sipo->editipo;
381         if(ei==0) return;
382         for(a=0; a<G.sipo->totipo; a++, ei++) {
383                 if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
384                         bezt= ei->icu->bezt;
385                         b= ei->icu->totvert;
386                         while(b--) {
387                                 
388                                 bezt->vec[0][0]= facx*(bezt->vec[0][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
389                                 bezt->vec[1][0]= facx*(bezt->vec[1][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
390                                 bezt->vec[2][0]= facx*(bezt->vec[2][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
391                         
392                                 bezt->vec[0][1]= facy*(bezt->vec[0][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
393                                 bezt->vec[1][1]= facy*(bezt->vec[1][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
394                                 bezt->vec[2][1]= facy*(bezt->vec[2][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
395
396                                 bezt++;
397                         }
398                 }
399         }
400
401         editipo_changed(G.sipo, 1);
402
403         BIF_undo_push("Scale Edit Ipo");
404         allqueue(REDRAWNLA, 0);
405         allqueue (REDRAWACTION, 0);
406         allqueue(REDRAWIPO, 0);
407 }
408
409 static void make_ob_editipo(Object *ob, SpaceIpo *si)
410 {
411         EditIpo *ei;
412         int a, len, colipo=0;
413         char *name;
414         
415         if(ob->type==OB_MESH) colipo= 1;
416
417         ei= si->editipo= MEM_callocN(OB_TOTIPO*sizeof(EditIpo), "editipo");
418         
419         si->totipo= OB_TOTIPO;
420         
421         for(a=0; a<OB_TOTIPO; a++) {
422                 name = getname_ob_ei(ob_ar[a], colipo);
423                 strcpy(ei->name, name);
424                 ei->adrcode= ob_ar[a];
425                 
426                 if ELEM6(ei->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z) ei->disptype= IPO_DISPDEGR;
427                 else if(ei->adrcode==OB_LAY) ei->disptype= IPO_DISPBITS;
428                 else if(ei->adrcode==OB_TIME) ei->disptype= IPO_DISPTIME;
429
430                 ei->col= ipo_rainbow(a, OB_TOTIPO);
431
432                 if(colipo) {
433                         len= strlen(ei->name);
434                         if(len) {
435                                 if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
436                                 else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
437                                 else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
438                         }
439                 }
440                 
441                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
442                 if(ei->icu) {
443                         ei->flag= ei->icu->flag;
444                 }
445                 
446                 
447                 ei++;
448         }
449         //fprintf(stderr,"FSIMAKE_OPBJ call %d \n", si->totipo);
450 }
451
452 static void make_part_editipo(SpaceIpo *si)
453 {
454         EditIpo *ei;
455         int a;
456         char *name;
457         
458         if(si->from==0) return;
459         
460         ei= si->editipo= MEM_callocN(PART_TOTIPO*sizeof(EditIpo), "editipo");
461         
462         si->totipo= PART_TOTIPO;
463         
464         for(a=0; a<PART_TOTIPO; a++) {
465                 name = getname_part_ei(part_ar[a]);
466                 strcpy(ei->name, name);
467                 ei->adrcode= part_ar[a];
468                 ei->col= ipo_rainbow(a, PART_TOTIPO);
469                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
470                 if(ei->icu) {
471                         ei->flag= ei->icu->flag;
472                 }
473                 
474                 ei++;
475         }
476 }
477
478 // copied from make_seq_editipo
479 static void make_fluidsim_editipo(SpaceIpo *si, Object *ob) // NT
480 {
481         EditIpo *ei;
482         int a;
483         char *name;
484         int numipos = FLUIDSIM_TOTIPO;
485         int ipo_start_index = 0;
486         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
487         FluidsimSettings *fss= fluidmd->fss;
488         
489         // we don't need all fluid ipos for all types! - dg
490         if(fss->type == OB_FLUIDSIM_CONTROL)
491         {
492                 numipos = 4; // there are 4 fluid control ipos
493                 ipo_start_index = 9;
494                 
495         }
496         else if(fss->type == OB_FLUIDSIM_DOMAIN)
497         {
498                 numipos = 5; // there are 5 ipos for fluid domains
499         }
500         else
501         {
502                 numipos = 4; // there are 4 for the rest
503                 ipo_start_index = 5;
504         }
505                 
506         ei= si->editipo= MEM_callocN(numipos*sizeof(EditIpo), "fluidsim_editipo");
507         si->totipo = numipos;
508         for(a=ipo_start_index; a<ipo_start_index+numipos; a++) {
509                 //fprintf(stderr,"FSINAME %d %d \n",a,fluidsim_ar[a], (int)(getname_fluidsim_ei(fluidsim_ar[a]))  );
510                 name = getname_fluidsim_ei(fluidsim_ar[a]);
511                 strcpy(ei->name, name);
512                 ei->adrcode= fluidsim_ar[a];
513                 ei->col= ipo_rainbow(a, numipos);
514                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
515                 if(ei->icu) {
516                         ei->flag = ei->icu->flag;
517                 } 
518                 //else { ei->flag |= IPO_VISIBLE; }
519                 //fprintf(stderr,"FSIMAKE eif%d,icuf%d icu%d %d|%d\n", ei->flag,ei->icu->flag, (int)ei->icu, IPO_VISIBLE,IPO_SELECT);
520                 //fprintf(stderr,"FSIMAKE eif%d icu%d %d|%d\n", ei->flag, (int)ei->icu, IPO_VISIBLE,IPO_SELECT);
521                 ei++;
522         }
523 }
524
525 static void make_seq_editipo(SpaceIpo *si)
526 {
527         EditIpo *ei;
528         int a;
529         char *name;
530         
531         ei= si->editipo= MEM_callocN(SEQ_TOTIPO*sizeof(EditIpo), "editipo");
532         
533         si->totipo= SEQ_TOTIPO;
534         
535         
536         for(a=0; a<SEQ_TOTIPO; a++) {
537                 name = getname_seq_ei(seq_ar[a]);
538                 strcpy(ei->name, name);
539                 ei->adrcode= seq_ar[a];
540                 
541                 ei->col= ipo_rainbow(a, SEQ_TOTIPO);
542                 
543                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
544                 if(ei->icu) {
545                         ei->flag= ei->icu->flag;
546                 }
547                 else ei->flag |= IPO_VISIBLE;
548                 
549                 ei++;
550         }
551 }
552
553 static void make_cu_editipo(SpaceIpo *si)
554 {
555         EditIpo *ei;
556         int a;
557         char *name;
558         
559         ei= si->editipo= MEM_callocN(CU_TOTIPO*sizeof(EditIpo), "editipo");
560         
561         si->totipo= CU_TOTIPO;
562         
563         
564         for(a=0; a<CU_TOTIPO; a++) {
565                 name = getname_cu_ei(cu_ar[a]);
566                 strcpy(ei->name, name);
567                 ei->adrcode= cu_ar[a];
568                 
569                 ei->col= ipo_rainbow(a, CU_TOTIPO);
570                 
571                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
572                 if(ei->icu) {
573                         ei->flag= ei->icu->flag;
574                 }
575                 else ei->flag |= IPO_VISIBLE;
576                  
577                 ei++;
578         }
579 }
580
581 static void make_key_editipo(SpaceIpo *si)
582 {
583         Key *key;
584         KeyBlock *kb=NULL;
585         EditIpo *ei;
586         int a;
587         
588         key= ob_get_key((Object *)G.sipo->from);
589         if(key==NULL) return;
590         
591         si->totipo= BLI_countlist(&key->block);
592         ei= si->editipo= MEM_callocN(si->totipo*sizeof(EditIpo), "editipo");
593         
594         for(a=0, kb= key->block.first; a<si->totipo; a++, ei++, kb= kb->next) {
595                 
596                 if(kb->name[0] != 0) strncpy(ei->name, kb->name, 31);   // length both same
597                 ei->adrcode= kb->adrcode;
598                 
599                 ei->col= ipo_rainbow(a, KEY_TOTIPO);
600                 
601                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
602                 if(ei->icu) {
603                         ei->flag= ei->icu->flag;
604                 }
605                 else if(a==0) 
606                         if(key && key->type==KEY_NORMAL)
607                                 ei->flag |= IPO_VISIBLE;
608                 
609                 /* active ipo is tied to active shape  */
610                 {
611                         Object *ob= OBACT;
612                         if(a==ob->shapenr-1)
613                                 set_active_editipo(ei);
614                 }
615         }
616         
617         ei= si->editipo;
618         if(key && key->type==KEY_RELATIVE) {
619                 strcpy(ei->name, "----");
620         }
621         else {
622                 ei->flag |= IPO_VISIBLE;
623         }
624 }
625
626 static void make_mat_editipo(SpaceIpo *si)
627 {
628         EditIpo *ei;
629         int a, len;
630         char *name;
631         
632         if(si->from==0) return;
633         
634         ei= si->editipo= MEM_callocN(MA_TOTIPO*sizeof(EditIpo), "editipo");
635         
636         si->totipo= MA_TOTIPO;
637         
638         for(a=0; a<MA_TOTIPO; a++) {
639                 name = getname_mat_ei(ma_ar[a]);
640                 strcpy(ei->name, name);
641                 ei->adrcode= ma_ar[a];
642                 
643                 if(ei->adrcode & MA_MAP1) {
644                         ei->adrcode-= MA_MAP1;
645                         ei->adrcode |= texchannel_to_adrcode(si->channel);
646                 }
647                 else {
648                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
649                 }
650                 
651                 ei->col= ipo_rainbow(a, MA_TOTIPO);
652                 
653                 len= strlen(ei->name);
654                 if(len) {
655                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
656                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
657                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
658                 }
659                 
660                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
661                 if(ei->icu) {
662                         ei->flag= ei->icu->flag;
663                 }
664                 
665                 ei++;
666         }
667 }
668
669 static void make_texture_editipo(SpaceIpo *si)
670 {
671         EditIpo *ei;
672         int a, len;
673         char *name;
674         
675         if(si->from==0) return;    
676         
677         ei= si->editipo= MEM_callocN(TE_TOTIPO*sizeof(EditIpo), "editipo");
678         
679         si->totipo= TE_TOTIPO;
680         
681         for(a=0; a<TE_TOTIPO; a++) {
682                 name = getname_tex_ei(te_ar[a]);
683                 strcpy(ei->name, name);
684                         ei->adrcode= te_ar[a];
685
686                 ei->col= ipo_rainbow(a, TE_TOTIPO);
687         
688                 len= strlen(ei->name);
689                 if(len) {
690                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
691                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
692                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
693                 }       
694                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
695                 if(ei->icu) {
696                         ei->flag= ei->icu->flag;
697                 }
698                 
699                 ei++;
700         }
701 }
702
703 static void make_world_editipo(SpaceIpo *si)
704 {
705         EditIpo *ei;
706         int a, len;
707         char *name;
708         
709         if(si->from==0) return;
710         
711         ei= si->editipo= MEM_callocN(WO_TOTIPO*sizeof(EditIpo), "editipo");
712         
713         si->totipo= WO_TOTIPO;
714         
715         for(a=0; a<WO_TOTIPO; a++) {
716                 name = getname_world_ei(wo_ar[a]);
717                 
718                 strcpy(ei->name, name); 
719                 ei->adrcode= wo_ar[a];
720                 
721                 if(ei->adrcode & MA_MAP1) {
722                         ei->adrcode-= MA_MAP1;
723                         ei->adrcode |= texchannel_to_adrcode(si->channel);
724                 }
725                 else {
726                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
727                 }
728                 
729                 ei->col= ipo_rainbow(a, WO_TOTIPO);
730                 
731                 len= strlen(ei->name);
732                 if(len) {
733                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
734                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
735                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
736                 }
737                 
738                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
739                 if(ei->icu) {
740                         ei->flag= ei->icu->flag;
741                 }
742                 
743                 ei++;
744         }
745 }
746
747 static void make_lamp_editipo(SpaceIpo *si)
748 {
749         EditIpo *ei;
750         int a;
751         char *name;
752         
753         ei= si->editipo= MEM_callocN(LA_TOTIPO*sizeof(EditIpo), "editipo");
754         
755         si->totipo= LA_TOTIPO;
756         
757         for(a=0; a<LA_TOTIPO; a++) {
758                 name = getname_la_ei(la_ar[a]);
759                 strcpy(ei->name, name);
760                 ei->adrcode= la_ar[a];
761
762                 if(ei->adrcode & MA_MAP1) {
763                         ei->adrcode-= MA_MAP1;
764                         ei->adrcode |= texchannel_to_adrcode(si->channel);
765                 }
766
767                 ei->col= ipo_rainbow(a, LA_TOTIPO);
768                 
769                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
770                 if(ei->icu) {
771                         ei->flag= ei->icu->flag;
772                 }
773                 
774                 ei++;
775         }
776 }
777
778 static void make_camera_editipo(SpaceIpo *si)
779 {
780         EditIpo *ei;
781         int a;
782         char *name;
783         
784         ei= si->editipo= MEM_callocN(CAM_TOTIPO*sizeof(EditIpo), "editipo");
785         
786         si->totipo= CAM_TOTIPO;
787         
788         
789         for(a=0; a<CAM_TOTIPO; a++) {
790                 name = getname_cam_ei(cam_ar[a]);
791                 strcpy(ei->name, name);
792                 ei->adrcode= cam_ar[a];
793
794                 ei->col= ipo_rainbow(a, CAM_TOTIPO);
795                 
796                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
797                 if(ei->icu) {
798                         ei->flag= ei->icu->flag;
799                 }
800                 
801                 ei++;
802         }
803 }
804
805 static int make_constraint_editipo(Ipo *ipo, EditIpo **si)
806 {
807         EditIpo *ei;
808         int a;
809         char *name;
810         
811         ei= *si= MEM_callocN(CO_TOTIPO*sizeof(EditIpo), "editipo");
812         
813         for(a=0; a<CO_TOTIPO; a++) {
814                 name = getname_co_ei(co_ar[a]);
815                 strcpy(ei->name, name);
816                 ei->adrcode= co_ar[a];
817
818                 ei->col= ipo_rainbow(a, CO_TOTIPO);
819                 
820                 ei->icu= find_ipocurve(ipo, ei->adrcode);
821                 if(ei->icu) {
822                         ei->flag= ei->icu->flag;
823                 }
824                 
825                 ei++;
826         }
827
828         return CO_TOTIPO;
829 }
830
831 static int make_bone_editipo(Ipo *ipo, EditIpo **si)
832 {
833         EditIpo *ei;
834         int a;
835         char *name;
836         
837         ei= *si= MEM_callocN(AC_TOTIPO*sizeof(EditIpo), "editipo");
838         
839         for(a=0; a<AC_TOTIPO; a++) {
840                 name = getname_ac_ei(ac_ar[a]);
841                 strcpy(ei->name, name);
842                 ei->adrcode= ac_ar[a];
843
844                 ei->col= ipo_rainbow(a, AC_TOTIPO);
845                 
846                 ei->icu= find_ipocurve(ipo, ei->adrcode);
847                 if(ei->icu) {
848                         ei->flag= ei->icu->flag;
849                 }
850                 
851                 ei++;
852         }
853
854         return AC_TOTIPO;
855 }
856
857 static void make_sound_editipo(SpaceIpo *si)
858 {
859         EditIpo *ei;
860         int a;
861         char *name;
862         
863         ei= si->editipo= MEM_callocN(SND_TOTIPO*sizeof(EditIpo), "editipo");
864         
865         si->totipo= SND_TOTIPO;
866         
867         
868         for(a=0; a<SND_TOTIPO; a++) {
869                 name = getname_snd_ei(snd_ar[a]);
870                 strcpy(ei->name, name);
871                 ei->adrcode= snd_ar[a];
872
873                 ei->col= ipo_rainbow(a, SND_TOTIPO);
874                 
875                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
876                 if(ei->icu) {
877                         ei->flag= ei->icu->flag;
878                 }
879                 
880                 ei++;
881         }
882 }
883
884 /* only called in test_editipo() below */
885 static void make_editipo(void)
886 {
887         EditIpo *ei;
888         Object *ob;
889         rctf *rf;
890         int a;
891
892         if(G.sipo->editipo)
893                 MEM_freeN(G.sipo->editipo);
894         
895         G.sipo->editipo= NULL;
896         G.sipo->totipo= 0;
897         
898         if(G.sipo->from==NULL) return;
899         
900         ob= OBACT;
901
902         if(G.sipo->ipo) G.sipo->showkey= G.sipo->ipo->showkey;
903
904         if(G.sipo->blocktype==ID_SEQ) {
905                 make_seq_editipo(G.sipo);
906         }
907         else if(G.sipo->blocktype==ID_WO) {
908                 make_world_editipo(G.sipo);
909         } 
910         else if(G.sipo->blocktype==ID_OB) {
911                 if (ob) {
912                         ob->ipowin= ID_OB;
913                         make_ob_editipo(ob, G.sipo);
914                 }
915         }
916         else if(G.sipo->blocktype==ID_MA) {
917                 if (ob) {
918                         ob->ipowin= ID_MA;
919                         make_mat_editipo(G.sipo);
920                 }
921         }
922         else if(G.sipo->blocktype==ID_CU) {
923                 if (ob) {
924                         ob->ipowin= ID_CU;
925                         make_cu_editipo(G.sipo);
926                 }
927         }
928         else if(G.sipo->blocktype==ID_KE) {
929                 if (ob) {
930                         ob->ipowin= ID_KE;
931                         make_key_editipo(G.sipo);
932                 }
933         }
934         else if(G.sipo->blocktype==ID_LA) {
935                 if (ob) {
936                         ob->ipowin= ID_LA;
937                         make_lamp_editipo(G.sipo);
938                 }
939         }
940         else if(G.sipo->blocktype==ID_TE) {
941                 if (ob) {
942                         ob->ipowin= ID_TE;
943                         make_texture_editipo(G.sipo);
944                 }
945                 else if(G.scene->world && give_current_world_texture()) {
946                         make_texture_editipo(G.sipo);
947                 }
948         }
949         else if(G.sipo->blocktype==ID_CA) {
950                 if (ob) {
951                         ob->ipowin= ID_CA;
952                         make_camera_editipo(G.sipo);
953                 }
954         }
955         else if(G.sipo->blocktype==ID_SO) {
956                 if (ob) {
957                         ob->ipowin= ID_SO;
958                         make_sound_editipo(G.sipo);
959                 }
960         }
961         else if(G.sipo->blocktype==ID_CO){
962                 G.sipo->totipo = make_constraint_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
963                 if (ob) {
964                         ob->ipowin= ID_CO;
965                 }
966         }
967         else if(G.sipo->blocktype==ID_PO) {
968
969                 G.sipo->totipo = make_bone_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
970                 if (ob) {
971                         ob->ipowin= ID_PO;
972                 }
973         }
974         else if(G.sipo->blocktype==ID_FLUIDSIM) {
975                 if (ob) { // NT
976                         ob->ipowin= ID_FLUIDSIM;
977                         make_fluidsim_editipo(G.sipo, ob);
978                 }
979         }
980         else if(G.sipo->blocktype==ID_PA) {
981                 if (ob) {
982                         ob->ipowin= ID_PA;
983                         make_part_editipo(G.sipo);
984                 }
985         }
986
987         if(G.sipo->editipo==0) return;
988         
989         ei= G.sipo->editipo;
990         for(a=0; a<G.sipo->totipo; a++, ei++) {
991                 if(ei->icu) ei->icu->flag= ei->flag;
992         }
993         editipo_changed(G.sipo, 0);
994         
995         /* sets globals, bad stuff but we need these variables in other parts of code */
996         get_status_editipo();
997         
998         
999         if (G.sipo->flag & SIPO_LOCK_VIEW) {
1000                 rf= &(G.v2d->cur); /* view is locked, dont move it, just to sanity check */
1001                 if(rf->xmin>=rf->xmax || rf->ymin>=rf->ymax) ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
1002         } else {
1003                 if(G.sipo->ipo) {
1004                         if (G.sipo->pin)
1005                                 rf= &(G.sipo->v2d.cur);
1006                         else
1007                                 rf= &(G.sipo->ipo->cur);
1008                         
1009                         if(rf->xmin<rf->xmax && rf->ymin<rf->ymax) G.v2d->cur= *rf;
1010                         else ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
1011                 }
1012                 else {
1013                         ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
1014                 }
1015         }
1016         view2d_do_locks(curarea, V2D_LOCK_COPY);
1017 }
1018
1019 /* evaluates context in the current UI */
1020 /* blocktype is type of ipo */
1021 /* from is the base pointer to find data to change (ob in case of action or pose) */
1022 /* bonename is for local bone ipos (constraint only now) */
1023 static void get_ipo_context(short blocktype, ID **from, Ipo **ipo, char *actname, char *constname, char *bonename)
1024 {
1025         Object *ob= OBACT;
1026         
1027         *from= NULL;
1028         *ipo= NULL;
1029         
1030         if(blocktype==ID_CO) {
1031                 if (ob) {
1032                         bConstraintChannel *chan;
1033                         bConstraint *con= get_active_constraint(ob);
1034                         
1035                         if(con) {
1036                                 *from= &ob->id;
1037                                 
1038                                 BLI_strncpy(constname, con->name, 32);
1039                                 
1040                                 /* a bit hackish, but we want con->ipo to work */
1041                                 if(con->flag & CONSTRAINT_OWN_IPO) {
1042                                         if(ob->flag & OB_POSEMODE) {
1043                                                 bPoseChannel *pchan= get_active_posechannel(ob);
1044                                                 if(pchan) {
1045                                                         BLI_strncpy(bonename, pchan->name, 32);
1046                                                         *ipo= con->ipo;
1047                                                 }
1048                                         }
1049                                 }
1050                                 else {
1051                                         chan= get_active_constraint_channel(ob);
1052                                         if(chan) {
1053                                                 *ipo= chan->ipo;
1054                                                 BLI_strncpy(constname, con->name, 32);
1055                                         }
1056                                         
1057                                         /* set actname if in posemode */
1058                                         if (ob->action) {
1059                                                 if (ob->flag & OB_POSEMODE) {
1060                                                         bPoseChannel *pchan= get_active_posechannel(ob);
1061                                                         if (pchan) {
1062                                                                 BLI_strncpy(actname, pchan->name, 32);
1063                                                                 BLI_strncpy(bonename, pchan->name, 32);
1064                                                         }
1065                                                 }
1066                                                 else if (ob->ipoflag & OB_ACTION_OB)
1067                                                         strcpy(actname, "Object");
1068                                         }
1069                                         else {
1070                                                 if (ob->flag & OB_POSEMODE) {
1071                                                         bPoseChannel *pchan= get_active_posechannel(ob);
1072                                                         if (pchan) {
1073                                                                 BLI_strncpy(actname, pchan->name, 32);
1074                                                                 BLI_strncpy(bonename, pchan->name, 32);
1075                                                         }
1076                                                 }
1077                                         }
1078                                 }
1079                         }
1080                 }
1081         }
1082         else if(blocktype==ID_PO) {
1083                 if (ob && ob->action && ob->type==OB_ARMATURE) {
1084                         bPoseChannel *pchan= get_active_posechannel(ob);
1085                         
1086                         *from= (ID *)ob;
1087                         if (pchan) {
1088                                 bActionChannel *achan;
1089                                 
1090                                 BLI_strncpy(actname, pchan->name, 32);  /* also set when no channel yet */
1091                                 
1092                                 achan= get_action_channel(ob->action, pchan->name);
1093                                 if(achan)
1094                                         *ipo= achan->ipo;
1095                         }
1096                 } 
1097                 
1098         }
1099         else if(blocktype==ID_OB) {
1100                 if(ob) {
1101                         *from= (ID *)ob;
1102                         if(ob->ipoflag & OB_ACTION_OB) {
1103                                 if (ob->action) {
1104                                         bActionChannel *achan= get_action_channel(ob->action, "Object");
1105                                         if(achan) {
1106                                                 *ipo= achan->ipo;
1107                                                 BLI_strncpy(actname, achan->name, 32);
1108                                         }
1109                                 }
1110                         }
1111                         else {
1112                                 *ipo= ob->ipo;
1113                         }
1114                 }
1115         }
1116         else if(blocktype==ID_SEQ) {
1117                 Sequence *last_seq = get_last_seq();
1118                 
1119                 if(last_seq) {
1120                         *from= (ID *)last_seq;
1121                         *ipo= last_seq->ipo;
1122                 }
1123         }
1124         else if(blocktype==ID_WO) {
1125                 World *wo= G.scene->world;
1126                 *from= (ID *)wo;
1127                 if(wo) *ipo= wo->ipo;
1128         }
1129         else if(blocktype==ID_TE) {
1130                 if(ob) {
1131                         Tex *tex= give_current_texture(ob, ob->actcol);
1132                         *from= (ID *)tex;
1133                         if(tex) *ipo= tex->ipo;
1134                 }
1135                 else if(G.scene->world) {
1136                         Tex *tex= give_current_world_texture();
1137                         *from= (ID *)tex;
1138                         if(tex) *ipo= tex->ipo;
1139                 }
1140         }
1141         else if(blocktype==ID_MA) {
1142                 if(ob) {
1143                         Material *ma= give_current_material(ob, ob->actcol);
1144                         ma= editnode_get_active_material(ma);
1145                         *from= (ID *)ma;
1146                         if(ma) *ipo= ma->ipo;
1147                 }
1148         }
1149         else if(blocktype==ID_KE) {
1150                 if(ob) {
1151                         Key *key= ob_get_key(ob);
1152                         
1153                         if(ob->ipoflag & OB_ACTION_KEY) {
1154                                 if (ob->action) {
1155                                         bActionChannel *achan= get_action_channel(ob->action, "Shape");
1156                                         if(achan) {
1157                                                 *ipo= achan->ipo;
1158                                                 BLI_strncpy(actname, achan->name, 32);
1159                                         }
1160                                 }
1161                         }
1162                         else if(key) *ipo= key->ipo;
1163                         
1164                         *from= (ID *)ob;
1165                 }
1166         }
1167         else if(blocktype==ID_CU) {
1168                 if(ob && ob->type==OB_CURVE) {
1169                         Curve *cu= ob->data;
1170                         *from= (ID *)cu;
1171                         *ipo= cu->ipo;
1172                 }
1173         }
1174         else if(blocktype==ID_LA) {
1175                 if(ob && ob->type==OB_LAMP) {
1176                         Lamp *la= ob->data;
1177                         *from= (ID *)la;
1178                         *ipo= la->ipo;
1179                 }
1180         }
1181         else if(blocktype==ID_CA) {
1182                 if(ob && ob->type==OB_CAMERA) {
1183                         Camera *ca= ob->data;
1184                         *from= (ID *)ca;
1185                         if(ca) *ipo= ca->ipo;
1186                 }
1187         }
1188         else if(blocktype==ID_SO) {
1189                 
1190                 //              if (G.buts && G.buts->mainb == BUTS_SOUND) {
1191                 //                      bSound *sound = G.buts->lockpoin;
1192                 //                      *from= (ID *)sound;
1193                 //                      if(sound) *ipo= sound->ipo;
1194                 //              }
1195         }
1196         else if(blocktype==ID_FLUIDSIM) {
1197                 if(ob)
1198                 {
1199                         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
1200                         if(fluidmd) {
1201                                 FluidsimSettings *fss= fluidmd->fss;
1202                                 *from= (ID *)ob;
1203                                 if(fss) *ipo= fss->ipo;
1204                         }
1205                 }
1206         }
1207         else if(blocktype==ID_PA) {
1208                 ParticleSystem *psys = psys_get_current(ob);
1209                 if(psys){
1210                         *from= (ID *)ob;
1211                         *ipo= psys->part->ipo;
1212                 }
1213         }
1214 }
1215
1216 /* called on each redraw, check if editipo data has to be remade */
1217 /* if doit already set, it always makes (in case no ipo exists, we need to see the channels */
1218 void test_editipo(int doit)
1219 {
1220         
1221         if(G.sipo->pin==0) {
1222                 Ipo *ipo;
1223                 ID *from;
1224                 char actname[32]="", constname[32]="", bonename[32]="";
1225                 
1226                 get_ipo_context(G.sipo->blocktype, &from, &ipo, actname, constname, bonename);
1227                 
1228                 if(G.sipo->ipo != ipo) {
1229                         G.sipo->ipo= ipo;
1230                         /* if lock we don't copy from ipo, this makes the UI jump around confusingly */
1231                         if(G.v2d->flag & V2D_VIEWLOCK || G.sipo->flag & SIPO_LOCK_VIEW);
1232                         else if(ipo) G.v2d->cur= ipo->cur;
1233                         doit= 1;
1234                 }
1235                 if(G.sipo->from != from) {
1236                         G.sipo->from= from;
1237                         doit= 1;
1238                 }
1239                 if( strcmp(G.sipo->actname, actname)) {
1240                         BLI_strncpy(G.sipo->actname, actname, 32);
1241                         doit= 1;
1242                 }
1243                 if( strcmp(G.sipo->constname, constname)) {
1244                         BLI_strncpy(G.sipo->constname, constname, 32);
1245                         doit= 1;
1246                 }
1247                 if( strcmp(G.sipo->bonename, bonename)) {
1248                         BLI_strncpy(G.sipo->bonename, bonename, 32);
1249                         /* urmf; if bonename, then no action */
1250                         if(bonename[0]) G.sipo->actname[0]= 0;
1251                         doit= 1;
1252                 }
1253                 
1254                 if(G.sipo->ipo)
1255                         G.sipo->ipo->cur = G.v2d->cur;
1256                 
1257         }
1258                 
1259         if(G.sipo->editipo==NULL || doit) {
1260                 make_editipo();
1261         }
1262 }
1263
1264 /* ****************** EditIpo ************************ */
1265
1266 int totipo_edit=0, totipo_sel=0, totipo_curve=0, totipo_vis=0, totipo_vert=0, totipo_vertsel=0, totipo_key=0, totipo_keysel=0;
1267
1268 void get_status_editipo(void)
1269 {
1270         EditIpo *ei;
1271         IpoKey *ik;
1272         BezTriple *bezt;
1273         int a, b;
1274         
1275         totipo_vis= 0;
1276         totipo_curve= 0;
1277         totipo_sel= 0;
1278         totipo_edit= 0;
1279         totipo_vert= 0;
1280         totipo_vertsel= 0;
1281         totipo_key= 0;
1282         totipo_keysel= 0;
1283         
1284         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1285         
1286         ei= G.sipo->editipo;
1287         if(ei==0) return;
1288         for(a=0; a<G.sipo->totipo; a++) {
1289                 if( ei->flag & IPO_VISIBLE ) {
1290                         totipo_vis++;
1291                         if(ei->flag & IPO_SELECT) totipo_sel++;
1292                         if(ei->icu && ei->icu->totvert) totipo_curve++;
1293                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
1294                                 
1295                                 /* if showkey: do count the vertices (for grab) */
1296                                 if(G.sipo->showkey==0) totipo_edit++;
1297                                 
1298                                 if(ei->icu) {
1299                                         if(ei->icu->bezt) {
1300                                                 bezt= ei->icu->bezt;
1301                                                 b= ei->icu->totvert;
1302                                                 while(b--) {
1303                                                         if(ei->icu->ipo==IPO_BEZ) {
1304                                                                 if(bezt->f1 & SELECT) totipo_vertsel++;
1305                                                                 if(bezt->f3 & SELECT) totipo_vertsel++;
1306                                                                 totipo_vert+= 2;
1307                                                         }
1308                                                         if(bezt->f2 & SELECT) totipo_vertsel++;
1309                                                         
1310                                                         totipo_vert++;
1311                                                         bezt++;
1312                                                 }
1313                                         }
1314                                 }
1315                         }
1316                 }
1317                 ei++;
1318         }
1319         
1320         if(G.sipo->showkey) {
1321                 ik= G.sipo->ipokey.first;
1322                 while(ik) {
1323                         totipo_key++;
1324                         if(ik->flag & 1) totipo_keysel++;
1325                         ik= ik->next;
1326                 }
1327         }
1328 }
1329
1330 /* synchronize editipo flag with icu flag and ipokey flags */
1331 void update_editipo_flags(void)
1332 {
1333         EditIpo *ei;
1334         IpoKey *ik;
1335         int a;
1336         
1337         ei= G.sipo->editipo;
1338         if(ei) {
1339                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1340                         if(ei->icu) ei->icu->flag= ei->flag;
1341                 }
1342         }
1343         if(G.sipo->showkey) {
1344                 ik= G.sipo->ipokey.first;
1345                 while(ik) {
1346                         for(a=0; a<G.sipo->totipo; a++) {
1347                                 if(ik->data[a]) {
1348                                         if(ik->flag & 1) {
1349                                                 BEZ_SEL(ik->data[a]);
1350                                         }
1351                                         else {
1352                                                 BEZ_DESEL(ik->data[a]);
1353                                         }
1354                                 }
1355                         }
1356                         ik= ik->next;
1357                 }
1358         }
1359 }
1360
1361 /* sort of enter/leave editmode for curves */
1362 void set_editflag_editipo(void)
1363 {
1364         EditIpo *ei;
1365         int a; /*  , tot= 0, ok= 0; */
1366         
1367         /* after showkey immediately go to editing of selected points */
1368         if(G.sipo->showkey) {
1369                 G.sipo->showkey= 0;
1370                 if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
1371                 ei= G.sipo->editipo;
1372                 for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
1373                 scrarea_queue_headredraw(curarea);
1374                 allqueue(REDRAWVIEW3D, 0);
1375         }
1376         
1377         get_status_editipo();
1378         
1379         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1380         
1381         ei= G.sipo->editipo;
1382         for(a=0; a<G.sipo->totipo; a++, ei++) {         
1383                 if(ei->icu) {
1384                         if(ei->flag & IPO_VISIBLE) {
1385                                 
1386                                 if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
1387                                         ei->flag |= IPO_EDIT;
1388                                         ei->icu->flag= ei->flag;
1389                                 }
1390                                 else if(totipo_edit && (ei->flag & IPO_EDIT)) {
1391                                         ei->flag -= IPO_EDIT;
1392                                         ei->icu->flag= ei->flag;
1393                                 }
1394                                 else if(totipo_vis==1) {
1395                                         if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
1396                                         else ei->flag |= IPO_EDIT;
1397                                         ei->icu->flag= ei->flag;
1398                                 }
1399                         }
1400                 }
1401         }
1402         scrarea_queue_headredraw(curarea);
1403         scrarea_queue_winredraw(curarea);
1404 }
1405
1406 static short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
1407 {
1408         /* selected verts get a disadvantage */
1409         /* in icu and (bezt or bp) the nearest is written */
1410         /* return 0 1 2: handlepunt */
1411         EditIpo *ei;
1412         BezTriple *bezt1;
1413         int dist= 100, temp, a, b;
1414         short mval[2], hpoint=0, sco[3][2];
1415
1416         *icu= 0;
1417         *bezt= 0;
1418
1419         getmouseco_areawin(mval);
1420
1421         ei= G.sipo->editipo;
1422         for(a=0; a<G.sipo->totipo; a++, ei++) {
1423                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
1424                         
1425                         if(ei->icu->bezt) {
1426                                 bezt1= ei->icu->bezt;
1427                                 b= ei->icu->totvert;
1428                                 while(b--) {
1429
1430                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], sco[0]);
1431                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], sco[1]);
1432                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], sco[2]);
1433                                                                                 
1434                                         if(ei->disptype==IPO_DISPBITS) {
1435                                                 temp= abs(mval[0]- sco[1][0]);
1436                                         }
1437                                         else temp= abs(mval[0]- sco[1][0])+ abs(mval[1]- sco[1][1]);
1438
1439                                         if( bezt1->f2 & SELECT) temp+=5;
1440                                         if(temp<dist) { 
1441                                                 hpoint= 1; 
1442                                                 *bezt= bezt1; 
1443                                                 dist= temp; 
1444                                                 *icu= ei->icu; 
1445                                         }
1446                                         
1447                                         if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
1448                                                 /* middle points get an advantage */
1449                                                 temp= -3+abs(mval[0]- sco[0][0])+ abs(mval[1]- sco[0][1]);
1450                                                 if( bezt1->f1 & SELECT) temp+=5;
1451                                                 if(temp<dist) { 
1452                                                         hpoint= 0; 
1453                                                         *bezt= bezt1; 
1454                                                         dist= temp; 
1455                                                         *icu= ei->icu; 
1456                                                 }
1457                 
1458                                                 temp= abs(mval[0]- sco[2][0])+ abs(mval[1]- sco[2][1]);
1459                                                 if( bezt1->f3 & 1) temp+=5;
1460                                                 if(temp<dist) { 
1461                                                         hpoint= 2; 
1462                                                         *bezt=bezt1; 
1463                                                         dist= temp; 
1464                                                         *icu= ei->icu; 
1465                                                 }
1466                                         }
1467                                         bezt1++;
1468                                 }
1469                         }
1470                 }
1471         }
1472
1473         return hpoint;
1474 }
1475
1476 void mouse_select_ipo(void)
1477 {
1478         Object *ob;
1479         KeyBlock *actkb=NULL;
1480         EditIpo *ei, *actei= 0;
1481         IpoCurve *icu;
1482         IpoKey *ik, *actik;
1483         BezTriple *bezt;
1484         TimeMarker *marker;
1485         float x, y, dist, mindist;
1486         int a, oldflag = 0, hand, ok;
1487         short mval[2], xo, yo;
1488         
1489         if(G.sipo->editipo==0) return;
1490         
1491         get_status_editipo();
1492         marker=find_nearest_marker(SCE_MARKERS, 1);
1493         
1494         /* map ipo-points for editing if scaled ipo */
1495         if (NLA_IPO_SCALED) {
1496                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
1497         }
1498         
1499         if(G.sipo->showkey) {
1500                 float pixelwidth;
1501                 
1502                 view2d_getscale(G.v2d, &pixelwidth, NULL);
1503                 
1504                 getmouseco_areawin(mval);
1505                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1506                 actik= 0;
1507                 mindist= 1000.0;
1508                 ik= G.sipo->ipokey.first;
1509                 while(ik) {
1510                         dist= (float)(fabs(ik->val-x));
1511                         if(ik->flag & SELECT) dist+= pixelwidth;
1512                         if(dist < mindist) {
1513                                 actik= ik;
1514                                 mindist= dist;
1515                         }
1516                         ik= ik->next;
1517                 }
1518                 if(actik) {
1519                         oldflag= actik->flag;
1520                         
1521                         if(G.qual & LR_SHIFTKEY);
1522                         else deselectall_editipo();
1523                         
1524                         if(G.qual & LR_SHIFTKEY) {
1525                                 if(oldflag & 1) actik->flag &= ~1;
1526                                 else actik->flag |= 1;
1527                         }
1528                         else {
1529                                 actik->flag |= 1;
1530                         }
1531                 }
1532         }
1533         else if(totipo_edit) {
1534                 
1535                 hand= findnearest_ipovert(&icu, &bezt);
1536                 
1537                 if(G.qual & LR_SHIFTKEY) {
1538                         if(bezt) {
1539                                 if(hand==1) {
1540                                         if(BEZSELECTED(bezt)) {
1541                                                 BEZ_DESEL(bezt);
1542                                         }
1543                                         else {
1544                                                 BEZ_SEL(bezt);
1545                                         }
1546                                 }
1547                                 else if(hand==0) {
1548                                         if(bezt->f1 & SELECT) bezt->f1 &= ~SELECT;
1549                                         else bezt->f1= SELECT;
1550                                 }
1551                                 else {
1552                                         if(bezt->f3 & SELECT) bezt->f3 &= ~SELECT;
1553                                         else bezt->f3= SELECT;
1554                                 }
1555                         }                               
1556                 }
1557                 else {
1558                         deselectall_editipo();
1559                         
1560                         if(bezt) {
1561                                 if(hand==1) {
1562                                         BEZ_SEL(bezt);
1563                                 }
1564                                 else if(hand==0) bezt->f1 |= SELECT;
1565                                 else bezt->f3 |= SELECT;
1566                         }
1567                 }
1568         }
1569         else if (marker) {
1570                 /* select timeline marker */
1571                 if ((G.qual & LR_SHIFTKEY)==0) {
1572                         oldflag= marker->flag;
1573                         deselect_markers(0, 0);
1574                         
1575                         if (oldflag & SELECT)
1576                                 marker->flag &= ~SELECT;
1577                         else
1578                                 marker->flag |= SELECT;
1579                 }
1580                 else {
1581                         marker->flag |= SELECT;                         
1582                 }               
1583         }
1584         else {
1585                 
1586                 /* vertex keys ? */
1587                 if(G.sipo->blocktype==ID_KE && G.sipo->from) {
1588                         Key *key;
1589                         KeyBlock *kb, *curkb;
1590                         int i, index= 1;
1591                         
1592                         ob= (Object *)G.sipo->from;
1593                         key= ob_get_key(ob);
1594                         curkb= BLI_findlink(&key->block, ob->shapenr-1);
1595                         
1596                         ei= G.sipo->editipo;
1597                         if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
1598                                 getmouseco_areawin(mval);
1599                                 
1600                                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1601                                 /* how much is 20 pixels? */
1602                                 mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
1603                                 
1604                                 for(i=1, kb= key->block.first; kb; kb= kb->next, i++) {
1605                                         dist= (float)(fabs(kb->pos-y));
1606                                         if(kb==curkb) dist+= (float)0.01;
1607                                         if(dist < mindist) {
1608                                                 actkb= kb;
1609                                                 mindist= dist;
1610                                                 index= i;
1611                                         }
1612                                 }
1613                                 if(actkb) {
1614                                         ok= TRUE;
1615                                         if(G.obedit && actkb!=curkb) {
1616                                                 ok= okee("Copy key after leaving Edit Mode");
1617                                         }
1618                                         if(ok) {
1619                                                 /* also does all keypos */
1620                                                 deselectall_editipo();
1621                                                 set_active_key(index);
1622                                                 set_active_editipo(ei+index-1);
1623                                         }
1624                                 }
1625                         }
1626                 }
1627                 
1628                 /* select curve */
1629                 if(actkb==NULL) {
1630                         if(totipo_vis==1) {
1631                                 ei= G.sipo->editipo;
1632                                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1633                                         if(ei->icu) {
1634                                                 if(ei->flag & IPO_VISIBLE) actei= ei;
1635                                         }
1636                                 }
1637                         }
1638                         else if(totipo_vis>1) {
1639                                 actei= select_proj_ipo(0, 0);
1640                         }
1641                         
1642                         if(actei) oldflag= actei->flag;
1643                         
1644                         if(G.qual & LR_SHIFTKEY);
1645                         else deselectall_editipo();
1646                         
1647                         if(actei) {
1648                                 if(G.qual & LR_SHIFTKEY) {
1649                                         if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
1650                                         else actei->flag |= IPO_SELECT;
1651                                 }
1652                                 else {
1653                                         actei->flag |= IPO_SELECT;
1654                                 }
1655                                 set_active_editipo(actei);
1656                         }
1657                 }
1658         }
1659         
1660         /* undo mapping of ipo-points for editing if scaled ipo */
1661         if (NLA_IPO_SCALED) {
1662                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
1663         }
1664         
1665         update_editipo_flags();
1666         
1667         force_draw(0);
1668         BIF_undo_push("Select Ipo");
1669         
1670         if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
1671                 ob= OBACT;
1672                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
1673         }
1674         /* points inside of curve are drawn selected too */
1675         if(G.sipo->blocktype==ID_CU)
1676                 allqueue(REDRAWVIEW3D, 0);
1677         
1678         getmouseco_areawin(mval);
1679         xo= mval[0]; 
1680         yo= mval[1];
1681         
1682         while (get_mbut() & ((U.flag & USER_LMOUSESELECT)?L_MOUSE:R_MOUSE)) {           
1683                 getmouseco_areawin(mval);
1684                 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
1685                         
1686                         if (marker) {
1687                                 transform_markers('g', 0);
1688                         }
1689                         else {
1690                                 if(actkb) move_keys(OBACT);
1691                                 else transform_ipo('g');
1692                         }
1693                         
1694                         return;
1695                 }
1696                 BIF_wait_for_statechange();
1697         }
1698 }
1699
1700
1701 /* *********************************** */
1702
1703 /* handling of right-hand channel/curve buttons in ipo window */
1704 void do_ipowin_buts(short event)
1705 {
1706         EditIpo *ei = NULL;
1707         int a;
1708
1709         /* without shift, all other channels are made invisible */
1710         if((G.qual & LR_SHIFTKEY)==0) {
1711                 if(event>G.sipo->totipo) return;
1712                 ei = G.sipo->editipo;
1713                 for(a=0; a<G.sipo->totipo; a++) {
1714                         if(a!=event) ei->flag &= ~IPO_VISIBLE;
1715                         else ei->flag |= IPO_VISIBLE;
1716                         ei++;
1717                 }
1718         }
1719         
1720         /* set active */
1721         if(event>=0 && event<G.sipo->totipo) {
1722                 ei= G.sipo->editipo;    // void pointer...
1723                 set_active_editipo(ei+event);
1724                 set_active_key(event+1);        // only if there's a key, of course
1725         }
1726         scrarea_queue_winredraw(curarea);
1727         
1728         update_editipo_flags();
1729         get_status_editipo();
1730
1731         if(G.sipo->showkey) {
1732                 make_ipokey();
1733                 if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
1734         }
1735
1736 }
1737
1738 /* the fake buttons to the left of channel names, for select/deselect curves */
1739 void do_ipo_selectbuttons(void)
1740 {
1741         EditIpo *ei, *ei1;
1742         int a, nr;
1743         short mval[2];
1744         
1745         if(G.sipo->showkey) return;
1746         
1747         /* do not allow editipo here: convert editipos to selected */
1748         get_status_editipo();
1749         if(totipo_edit) {
1750                 set_editflag_editipo();
1751         }
1752         
1753         /* which */
1754         getmouseco_areawin(mval);
1755
1756         nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
1757         if(G.sipo->blocktype==ID_KE) nr--;              /* keys show something else in first channel */
1758         
1759         if(nr>=0 && nr<G.sipo->totipo) {
1760                 ei= G.sipo->editipo;
1761                 ei+= nr;
1762                 
1763                 set_active_editipo(ei);
1764                 set_active_key(nr+1);
1765
1766                 if(ei->icu) {
1767                         if((ei->flag & IPO_VISIBLE)==0) {
1768                                 ei->flag |= IPO_VISIBLE|IPO_SELECT;
1769                         }
1770         
1771                         if((G.qual & LR_SHIFTKEY)==0) {
1772                                 ei1= G.sipo->editipo;
1773                                 for(a=0; a<G.sipo->totipo; a++) {
1774                                         ei1->flag &= ~IPO_SELECT;
1775                                         ei1++;
1776                                 }
1777                         }
1778
1779                         if(ei->flag & IPO_SELECT) {
1780                                 ei->flag &= ~IPO_SELECT;
1781                         }
1782                         else {
1783                                 ei->flag |= IPO_SELECT;
1784                         }
1785                         
1786                         update_editipo_flags();
1787                         scrarea_queue_winredraw(curarea);
1788                 }
1789         }
1790         BIF_undo_push("Select Ipo curve");
1791 }
1792
1793 /* ********************************* Inserting keys ********************************************* */
1794
1795 /* depending type, it returns ipo, if needed it creates one */
1796 /* returns either action ipo or "real" ipo */
1797 /* arguments define full context;
1798    - *from has to be set always, to Object in case of Actions
1799    - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too)
1800    - if actname, use this to locate actionchannel, and optional constname 
1801    - if bonename, the constname is the ipo to the constraint
1802 */
1803
1804 /* note: check header_ipo.c, spaceipo_assign_ipo() too */
1805 Ipo *verify_ipo(ID *from, short blocktype, char *actname, char *constname, char *bonename, short add)
1806 {
1807         /* lib-linked data is not appropriate here */
1808         if ((from==NULL) || (from->lib))
1809                 return NULL;
1810         
1811         /* first check action ipos */
1812         if (actname && actname[0]) {
1813                 Object *ob= (Object *)from;
1814                 bActionChannel *achan;
1815                 
1816                 if (GS(from->name)!=ID_OB) {
1817                         printf("called ipo system for action with wrong base pointer\n");
1818                         return NULL;
1819                 }
1820                 
1821                 if ((ob->action==NULL) && (add))
1822                         ob->action= add_empty_action("Action");
1823                 
1824                 if (add)
1825                         achan= verify_action_channel(ob->action, actname);
1826                 else    
1827                         achan= get_action_channel(ob->action, actname);
1828                 
1829                 if (achan) {
1830                         /* automatically assign achan to act-group based on pchan's grouping */
1831                         if ((blocktype == ID_PO) && (add))
1832                                 verify_pchan2achan_grouping(ob->action, ob->pose, actname);
1833                         
1834                         /* constraint exception */
1835                         if (blocktype==ID_CO) {
1836                                 bConstraintChannel *conchan;
1837                                 
1838                                 if (add)
1839                                         conchan= verify_constraint_channel(&achan->constraintChannels, constname);
1840                                 else
1841                                         conchan= get_constraint_channel(&achan->constraintChannels, constname);
1842                                         
1843                                 if (conchan) {
1844                                         if ((conchan->ipo==NULL) && (add))
1845                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1846                                         return conchan->ipo;
1847                                 }
1848                         }
1849                         else {
1850                                 if ((achan->ipo==NULL) && (add))
1851                                         achan->ipo= add_ipo("ActIpo", blocktype);
1852                                 return achan->ipo;
1853                         }
1854                 }
1855         }
1856         else {
1857                 switch (GS(from->name)) {
1858                 case ID_OB:
1859                         {
1860                                 Object *ob= (Object *)from;
1861                                 
1862                                 /* constraint exception */
1863                                 if (blocktype==ID_CO) {
1864                                         /* check the local constraint ipo */
1865                                         if (bonename && bonename[0] && ob->pose) {
1866                                                 bPoseChannel *pchan= get_pose_channel(ob->pose, bonename);
1867                                                 bConstraint *con;
1868                                                 
1869                                                 for (con= pchan->constraints.first; con; con= con->next) {
1870                                                         if (strcmp(con->name, constname)==0)
1871                                                                 break;
1872                                                 }
1873                                                 
1874                                                 if (con) {
1875                                                         if ((con->ipo==NULL) && (add))
1876                                                                 con->ipo= add_ipo("CoIpo", ID_CO);
1877                                                         return con->ipo;
1878                                                 }
1879                                         }
1880                                         else { /* the actionchannel */
1881                                                 bConstraintChannel *conchan;
1882                                                 
1883                                                 if (add)
1884                                                         conchan= verify_constraint_channel(&ob->constraintChannels, constname);
1885                                                 else
1886                                                         conchan= get_constraint_channel(&ob->constraintChannels, constname);
1887                                                         
1888                                                 if (conchan) {
1889                                                         if ((conchan->ipo==NULL) && (add))
1890                                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1891                                                         return conchan->ipo;
1892                                                 }
1893                                         }
1894                                 }
1895                                 else if (blocktype==ID_OB) {
1896                                         if ((ob->ipo==NULL) && (add))
1897                                                 ob->ipo= add_ipo("ObIpo", ID_OB);
1898                                         return ob->ipo;
1899                                 }
1900                                 else if (blocktype==ID_KE) {
1901                                         Key *key= ob_get_key((Object *)from);
1902                                         
1903                                         if (key) {
1904                                                 if ((key->ipo==NULL) && (add))
1905                                                         key->ipo= add_ipo("KeyIpo", ID_KE);
1906                                                 return key->ipo;
1907                                         }
1908                                         return NULL;
1909                                 }
1910                                 else if (blocktype== ID_FLUIDSIM) {
1911                                         Object *ob= (Object *)from;
1912
1913                                         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
1914                                         if(fluidmd) {
1915                                                 FluidsimSettings *fss= fluidmd->fss;
1916                                                 
1917                                                 if ((fss->ipo==NULL) && (add))
1918                                                         fss->ipo= add_ipo("FluidsimIpo", ID_FLUIDSIM);
1919                                                 return fss->ipo;
1920                                         }
1921                                 }
1922                                 else if(blocktype== ID_PA) {
1923                                         Object *ob= (Object *)from;
1924                                         ParticleSystem *psys= psys_get_current(ob);
1925                                         
1926                                         if (psys) {
1927                                                 if ((psys->part->ipo==NULL) && (add))
1928                                                         psys->part->ipo= add_ipo("ParticleIpo", ID_PA);
1929                                                 return psys->part->ipo;
1930                                         }
1931                                         return NULL;
1932                                 }
1933                         }
1934                         break;
1935                 case ID_MA:
1936                         {
1937                                 Material *ma= (Material *)from;
1938                                 
1939                                 if ((ma->ipo==NULL) && (add))
1940                                         ma->ipo= add_ipo("MatIpo", ID_MA);
1941                                 return ma->ipo;
1942                         }
1943                         break;
1944                 case ID_TE:
1945                         {
1946                                 Tex *tex= (Tex *)from;
1947                                 
1948                                 if ((tex->ipo==NULL) && (add))
1949                                         tex->ipo= add_ipo("TexIpo", ID_TE);
1950                                 return tex->ipo;
1951                         }
1952                         break;
1953                 case ID_SEQ:
1954                         {
1955                                 Sequence *seq= (Sequence *)from;        /* note, sequence is mimicing Id */
1956                                 
1957                                 if ((seq->ipo==NULL) && (add))
1958                                         seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1959                                 update_seq_ipo_rect(seq);
1960                                 return seq->ipo;
1961                         }
1962                         break;
1963                 case ID_CU:
1964                         {
1965                                 Curve *cu= (Curve *)from;
1966                                 
1967                                 if ((cu->ipo==NULL) && (add))
1968                                         cu->ipo= add_ipo("CuIpo", ID_CU);
1969                                 return cu->ipo;
1970                         }
1971                         break;
1972                 case ID_WO:
1973                         {
1974                                 World *wo= (World *)from;
1975                                 
1976                                 if ((wo->ipo==NULL) && (add))
1977                                         wo->ipo= add_ipo("WoIpo", ID_WO);
1978                                 return wo->ipo;
1979                         }
1980                         break;
1981                 case ID_LA:
1982                         {
1983                                 Lamp *la= (Lamp *)from;
1984                                 
1985                                 if ((la->ipo==NULL) && (add))
1986                                         la->ipo= add_ipo("LaIpo", ID_LA);
1987                                 return la->ipo;
1988                         }
1989                         break;
1990                 case ID_CA:
1991                         {
1992                                 Camera *ca= (Camera *)from;
1993                                 
1994                                 if ((ca->ipo==NULL) && (add))
1995                                         ca->ipo= add_ipo("CaIpo", ID_CA);
1996                                 return ca->ipo;
1997                         }
1998                         break;
1999                 case ID_SO:
2000                         {
2001                                 bSound *snd= (bSound *)from;
2002                                 
2003                                 if ((snd->ipo==NULL) && (add))
2004                                         snd->ipo= add_ipo("SndIpo", ID_SO);
2005                                 return snd->ipo;
2006                         }
2007                 }
2008         }
2009         
2010         return NULL;    
2011 }
2012
2013 /* returns and creates
2014  * Make sure functions check for NULL or they will crash!
2015  *  */
2016 IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, char *bonename, int adrcode, short add)
2017 {
2018         Ipo *ipo;
2019         IpoCurve *icu= NULL;
2020         
2021         /* return 0 if lib */
2022         /* creates ipo too (if add) */
2023         ipo= verify_ipo(from, blocktype, actname, constname, bonename, add);
2024         
2025         if (ipo && ipo->id.lib==NULL && from->lib==NULL) {
2026                 /* try to find matching curve */
2027                 for (icu= ipo->curve.first; icu; icu= icu->next) {
2028                         if (icu->adrcode==adrcode) 
2029                                 break;
2030                 }
2031                 
2032                 /* make a new one if none found (and can add) */
2033                 if ((icu==NULL) && (add)) {
2034                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
2035                         
2036                         icu->flag |= (IPO_VISIBLE|IPO_AUTO_HORIZ);
2037                         if (ipo->curve.first==NULL) 
2038                                 icu->flag |= IPO_ACTIVE;        /* first one added active */
2039                         
2040                         icu->blocktype= blocktype;
2041                         icu->adrcode= adrcode;
2042                         
2043                         set_icu_vars(icu);
2044                         
2045                         BLI_addtail(&ipo->curve, icu);
2046                         
2047                         switch (GS(from->name)) {
2048                                 case ID_SEQ: {
2049                                         Sequence *seq= (Sequence *)from;
2050                                         
2051                                         update_seq_icu_rects(seq);
2052                                         break;
2053                                 }
2054                         }
2055                 }
2056         }
2057         
2058         /* return ipo-curve */
2059         return icu;
2060 }
2061
2062
2063 void add_vert_ipo(void)
2064 {
2065         EditIpo *ei;
2066         float x, y;
2067         int val;
2068         short mval[2];
2069
2070         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2071         if(G.sipo->showkey) {
2072                 G.sipo->showkey= 0;
2073                 free_ipokey(&G.sipo->ipokey);
2074         }
2075         
2076         getmouseco_areawin(mval);
2077         
2078         if(mval[0]>G.v2d->mask.xmax) return;
2079         
2080         ei= get_active_editipo();
2081         if(ei==NULL) {
2082                 error("No active Ipo curve");
2083                 return;
2084         }
2085         ei->flag |= IPO_VISIBLE;        /* can happen it is active but not visible */
2086         
2087         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
2088         
2089         /* convert click-time to ipo-time */
2090         if (NLA_IPO_SCALED) {
2091                 x= get_action_frame(OBACT, x);
2092         }
2093         
2094         if(ei->icu==NULL) {
2095                 if(G.sipo->from) {
2096                         ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, G.sipo->bonename, ei->adrcode, 1);
2097                         if (ei->icu)
2098                                 ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ;     /* new curve could have been added, weak... */
2099                         else
2100                                 error("Cannot create an IPO curve, you may be using libdata");
2101                 }
2102         }
2103         if(ei->icu==NULL) return;
2104
2105         if(ei->disptype==IPO_DISPBITS) {
2106                 ei->icu->vartype= IPO_BITS;
2107                 val= (int)floor(y-0.5);
2108                 if(val<0) val= 0;
2109                 y= (float)(1 << val);
2110         }
2111         
2112         insert_vert_icu(ei->icu, x, y, 0);
2113
2114         /* to be sure: if icu was 0, or only 1 curve visible */
2115         ei->flag |= IPO_SELECT;
2116         ei->icu->flag= ei->flag;
2117         
2118         editipo_changed(G.sipo, 1);
2119         BIF_undo_push("Add Ipo vertex");
2120 }
2121
2122
2123 void insertkey_editipo(void)
2124 {
2125         EditIpo *ei;
2126         IpoKey *ik;
2127         ID *id;
2128         float *fp, cfra, *insertvals;
2129         int a, nr, ok, tot;
2130         short event;
2131         
2132         ei= get_active_editipo();
2133         if(ei && ei->icu && ei->icu->driver) 
2134                 event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
2135         else if(G.sipo->showkey)
2136                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
2137         else 
2138                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
2139         
2140         if(event<1) return;
2141         
2142         if(event==3) {
2143                 IpoDriver *driver= ei->icu->driver;
2144                 
2145                 if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
2146                 ei->icu->totvert= 0;
2147                 ei->icu->bezt= NULL;
2148                 
2149                 insert_vert_icu(ei->icu, 0.0f, 0.0f, 0);
2150                 
2151                 if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
2152                         if(ei->disptype==IPO_DISPDEGR)
2153                                 insert_vert_icu(ei->icu, 18.0f, 18.0f, 0);
2154                         else
2155                                 insert_vert_icu(ei->icu, 18.0f, 1.0f, 0);
2156                 }
2157                 else
2158                         insert_vert_icu(ei->icu, 1.0f, 1.0f, 0);
2159                 
2160                 ei->flag |= IPO_SELECT|IPO_VISIBLE;
2161                 ei->icu->flag= ei->flag;
2162                 ei->icu->extrap= IPO_DIR;
2163
2164                 do_ipo_buttons(B_IPOHOME);
2165         }
2166         else {
2167                 ei= G.sipo->editipo;
2168                 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
2169                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2170                         
2171                                 ok= 0;
2172                                 if(G.sipo->showkey) ok= 1;
2173                                 else if(ei->flag & IPO_SELECT) ok= 1;
2174
2175                                 if(ok) {
2176                                         /* count amount */
2177                                         if(event==1) tot= 1;
2178                                         else {
2179                                                 ik= G.sipo->ipokey.first;
2180                                                 tot= 0;
2181                                                 while(ik) {
2182                                                         if(ik->flag & 1) tot++;
2183                                                         ik= ik->next;
2184                                                 }
2185                                         }
2186                                         if(tot) {
2187                                         
2188                                                 /* correction for ob timeoffs */
2189                                                 cfra= frame_to_float(CFRA);
2190                                                 id= G.sipo->from;       
2191                                                 if(id && GS(id->name)==ID_OB ) {
2192                                                         Object *ob= (Object *)id;
2193                                                         if((ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0) ) {
2194                                                                 cfra-= give_timeoffset(ob)*G.scene->r.framelen;
2195                                                         }
2196                                                 }
2197                                                 else if(id && GS(id->name)==ID_SEQ) {
2198                                                         Sequence *last_seq = get_last_seq();    /* editsequence.c */
2199                                                         
2200                                                         if(last_seq && (last_seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
2201                                                                 cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
2202                                                         }
2203                                                 }
2204                                                 
2205                                                 /* convert cfra to ipo-time */
2206                                                 if (NLA_IPO_SCALED) {
2207                                                         cfra= get_action_frame(OBACT, cfra);
2208                                                 }
2209                                 
2210                                                 insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
2211                                                 /* make sure icu->curval is correct */
2212                                                 calc_ipo(G.sipo->ipo, cfra);
2213                                                 
2214                                                 if(event==1) {
2215                                                         insertvals[0]= cfra;
2216                                                         
2217                                                         insertvals[1]= ei->icu->curval;
2218                                                 }
2219                                                 else {
2220                                                         fp= insertvals;
2221                                                         ik= G.sipo->ipokey.first;
2222                                                         while(ik) {
2223                                                                 if(ik->flag & 1) {
2224                                                                         calc_ipo(G.sipo->ipo, ik->val);
2225
2226                                                                         fp[0]= ik->val;
2227                                                                         fp[1]= ei->icu->curval;
2228                                                                         fp+= 2;
2229                                                                 }
2230                                                                 ik= ik->next;
2231                                                         }
2232                                                 }
2233                                                 fp= insertvals;
2234                                                 for(a=0; a<tot; a++, fp+=2) {
2235                                                         insert_vert_icu(ei->icu, fp[0], fp[1], 0);
2236                                                 }
2237                                                 
2238                                                 MEM_freeN(insertvals);
2239                                                 calc_ipo(G.sipo->ipo, (float)CFRA);
2240                                         }
2241                                 }
2242                         }
2243                 }
2244         }
2245         BIF_undo_push("Insert Key Ipo");
2246         allqueue (REDRAWACTION, 0);
2247         allqueue(REDRAWNLA, 0);
2248         allqueue(REDRAWIPO, 0);
2249         allspace(REMAKEIPO, 0);
2250 }
2251
2252
2253 /* ****************************************************************************** */
2254
2255 void add_duplicate_editipo(void)
2256 {
2257         Object *ob;
2258         EditIpo *ei;
2259         IpoCurve *icu;
2260         BezTriple *bezt, *beztn, *newb;
2261         int tot, a, b;
2262         
2263         get_status_editipo();
2264         if(totipo_vertsel==0) return;
2265         
2266         ei= G.sipo->editipo;
2267         for(a=0; a<G.sipo->totipo; a++, ei++) {
2268                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2269                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2270                                 icu= ei->icu;
2271                                 
2272                                 /* how many points */
2273                                 tot= 0;
2274                                 b= icu->totvert;
2275                                 bezt= icu->bezt;
2276                                 while(b--) {
2277                                         if(bezt->f2 & SELECT) tot++;
2278                                         bezt++;
2279                                 }
2280                                 
2281                                 if(tot) {
2282                                         icu->totvert+= tot;
2283                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2284                                         bezt= icu->bezt;
2285                                         b= icu->totvert-tot;
2286                                         while(b--) {
2287                                                 *beztn= *bezt;
2288                                                 if(bezt->f2 & SELECT) {
2289                                                         BEZ_DESEL(beztn);
2290                                                         beztn++;
2291                                                         *beztn= *bezt;
2292                                                 }
2293                                                 beztn++;
2294                                                 bezt++;
2295                                         }
2296                                         MEM_freeN(icu->bezt);
2297                                         icu->bezt= newb;
2298                                         
2299                                         calchandles_ipocurve(icu);
2300                                 }
2301                         }
2302                 }
2303         }
2304         
2305         if(G.sipo->showkey) {
2306                 make_ipokey();
2307                 if(G.sipo->blocktype==ID_OB) {
2308                         ob= OBACT;
2309                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2310                 }
2311         }
2312         BIF_undo_push("Duplicate Ipo");
2313         transform_ipo('g');
2314 }
2315
2316 void remove_doubles_ipo(void)
2317 {
2318         EditIpo *ei;
2319         IpoKey *ik, *ikn;
2320         BezTriple *bezt, *newb, *new1;
2321         float val;
2322         int mode, a, b;
2323         
2324         ei= G.sipo->editipo;
2325         for(a=0; a<G.sipo->totipo; a++, ei++) {
2326                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2327                         
2328                         /* OR the curve is selected OR in editmode OR in keymode */
2329                         mode= 0;
2330                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2331                         else if(ei->flag & IPO_SELECT) mode= 2;
2332                         
2333                         if(mode) {
2334                                 bezt= ei->icu->bezt;
2335                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2336                                 *newb= *bezt;
2337                                 b= ei->icu->totvert-1;
2338                                 bezt++;
2339                                 while(b--) {
2340                                         
2341                                         /* can we remove? */
2342                                         if(mode==2 || (bezt->f2 & SELECT)) {
2343                                         
2344                                                 /* are the points different? */
2345                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2346                                                         newb++;
2347                                                         *newb= *bezt;
2348                                                 }
2349                                                 else {
2350                                                         /* median */
2351                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2352                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2353                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2354                                                         
2355                                                         newb->h1= newb->h2= HD_FREE;
2356                                                         
2357                                                         ei->icu->totvert--;
2358                                                 }
2359                                                 
2360                                         }
2361                                         else {
2362                                                 newb++;
2363                                                 *newb= *bezt;
2364                                         }
2365                                         bezt++;
2366                                 }
2367                                 
2368                                 MEM_freeN(ei->icu->bezt);
2369                                 ei->icu->bezt= new1;
2370                                 
2371                                 calchandles_ipocurve(ei->icu);                          
2372                         }
2373                 }
2374         }
2375         
2376         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2377
2378         /* remove double keys */
2379         if(G.sipo->showkey) {
2380                 ik= G.sipo->ipokey.first;
2381                 ikn= ik->next;
2382                 
2383                 while(ik && ikn) {
2384                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2385                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2386                                         val= (float)((ik->val + ikn->val)/2.0);
2387                                         
2388                                         for(a=0; a<G.sipo->totipo; a++) {
2389                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2390                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2391                                         }
2392                                 }
2393                         }
2394                         ik= ikn;
2395                         ikn= ikn->next;
2396
2397                 }
2398                 
2399                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2400
2401         }
2402         deselectall_editipo();
2403         BIF_undo_push("Remove Doubles (IPO)");
2404 }
2405
2406
2407 void clean_ipo(void) 
2408 {
2409         EditIpo *ei;
2410         short ok;
2411         int b;
2412         
2413         ok= fbutton(&G.scene->toolsettings->clean_thresh, 
2414                                 0.0000001f, 1.0, 0.001, 0.1,
2415                                 "Threshold");
2416         if (!ok) return;
2417         
2418         get_status_editipo();
2419
2420         ei= G.sipo->editipo;
2421         for(b=0; b<G.sipo->totipo; b++, ei++) {
2422                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2423                 
2424                         ok= 0;
2425                         if(G.sipo->showkey) ok= 1;
2426                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
2427                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
2428                         
2429                         if(ok) {
2430                                 /* only clean if ok */
2431                                 clean_ipo_curve(ei->icu);
2432                         }
2433                 }
2434         }
2435         
2436         editipo_changed(G.sipo, 1);
2437         BIF_undo_push("Clean IPO");
2438 }
2439
2440 void clean_ipo_curve(IpoCurve *icu)
2441 {
2442         BezTriple *old_bezts, *bezt, *beztn;
2443         BezTriple *lastb;
2444         int totCount, i;
2445         float thresh;
2446         
2447         /* check if any points  */
2448         if (icu == NULL || icu->totvert <= 1) 
2449                 return;
2450         
2451         /* get threshold for match-testing */
2452         thresh= G.scene->toolsettings->clean_thresh;
2453         
2454         /* make a copy of the old BezTriples, and clear IPO curve */
2455         old_bezts = icu->bezt;
2456         totCount = icu->totvert;        
2457         icu->bezt = NULL;
2458         icu->totvert = 0;
2459         
2460         /* now insert first keyframe, as it should be ok */
2461         bezt = old_bezts;
2462         insert_vert_icu(icu, bezt->vec[1][0], bezt->vec[1][1], 0);
2463         
2464         /* Loop through BezTriples, comparing them. Skip any that do 
2465          * not fit the criteria for "ok" points.
2466          */
2467         for (i=1; i<totCount; i++) {    
2468                 float prev[2], cur[2], next[2];
2469                 
2470                 /* get BezTriples and their values */
2471                 if (i < (totCount - 1)) {
2472                         beztn = (old_bezts + (i+1));
2473                         next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
2474                 }
2475                 else {
2476                         beztn = NULL;
2477                         next[0] = next[1] = 0.0f;
2478                 }
2479                 lastb= (icu->bezt + (icu->totvert - 1));
2480                 bezt= (old_bezts + i);
2481                 
2482                 /* get references for quicker access */
2483                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
2484                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
2485                 
2486                 /* check if current bezt occurs at same time as last ok */
2487                 if (IS_EQT(cur[0], prev[0], thresh)) {
2488                         /* If there is a next beztriple, and if occurs at the same time, only insert 
2489                          * if there is a considerable distance between the points, and also if the 
2490                          * current is further away than the next one is to the previous.
2491                          */
2492                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
2493                                 (IS_EQT(next[1], prev[1], thresh)==0)) 
2494                         {
2495                                 /* only add if current is further away from previous */
2496                                 if (cur[1] > next[1]) {
2497                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2498                                                 /* add new keyframe */
2499                                                 insert_vert_icu(icu, cur[0], cur[1], 0);
2500                                         }
2501                                 }
2502                         }
2503                         else {
2504                                 /* only add if values are a considerable distance apart */
2505                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2506                                         /* add new keyframe */
2507                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2508                                 }
2509                         }
2510                 }
2511                 else {
2512                         /* checks required are dependent on whether this is last keyframe or not */
2513                         if (beztn) {
2514                                 /* does current have same value as previous and next? */
2515                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2516                                         /* add new keyframe*/
2517                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2518                                 }
2519                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
2520                                         /* add new keyframe */
2521                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2522                                 }
2523                         }
2524                         else {  
2525                                 /* add if value doesn't equal that of previous */
2526                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2527                                         /* add new keyframe */
2528                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2529                                 }
2530                         }
2531                 }
2532         }
2533         
2534         /* now free the memory used by the old BezTriples */
2535         if (old_bezts)
2536                 MEM_freeN(old_bezts);
2537 }
2538
2539
2540 /* temp struct used for smooth_ipo */
2541 typedef struct tSmooth_Bezt {
2542         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
2543 } tSmooth_Bezt;
2544
2545 void smooth_ipo(void)
2546 {
2547         EditIpo *ei;
2548         short ok;
2549         int b;
2550         
2551         get_status_editipo();
2552
2553         ei= G.sipo->editipo;
2554         for(b=0; b<G.sipo->totipo; b++, ei++) {
2555                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2556                         ok= 0;
2557                         if(G.sipo->showkey) ok= 1;
2558                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
2559                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
2560                         
2561                         if(ok) {
2562                                 IpoCurve *icu= ei->icu;
2563                                 BezTriple *bezt;
2564                                 int i, x, totSel = 0;
2565                                 
2566                                 /* check if enough points */
2567                                 if (icu->totvert >= 3) {
2568                                         /* first loop through - count how many verts are selected, and fix up handles */
2569                                         bezt= icu->bezt;
2570                                         for (i=0; i < icu->totvert; i++, bezt++) {                                              
2571                                                 if (BEZSELECTED(bezt)) {                                                        
2572                                                         /* line point's handles up with point's vertical position */
2573                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2574                                                         if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
2575                                                         if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
2576                                                         
2577                                                         /* add value to total */
2578                                                         totSel++;
2579                                                 }
2580                                         }
2581                                         
2582                                         /* if any points were selected, allocate tSmooth_Bezt points to work on */
2583                                         if (totSel >= 3) {
2584                                                 tSmooth_Bezt *tarray, *tsb;
2585                                                 
2586                                                 /* allocate memory in one go */
2587                                                 tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
2588                                                 
2589                                                 /* populate tarray with data of selected points */
2590                                                 bezt= icu->bezt;
2591                                                 for (i=0, x=0; (i < icu->totvert) && (x < totSel); i++, bezt++) {
2592                                                         if (BEZSELECTED(bezt)) {
2593                                                                 /* tsb simply needs pointer to vec, and index */
2594                                                                 tsb->h1 = &bezt->vec[0][1];
2595                                                                 tsb->h2 = &bezt->vec[1][1];
2596                                                                 tsb->h3 = &bezt->vec[2][1];
2597                                                                 
2598                                                                 /* advance to the next tsb to populate */
2599                                                                 if (x < totSel- 1) 
2600                                                                         tsb++;
2601                                                                 else
2602                                                                         break;
2603                                                         }
2604                                                 }
2605                                                 
2606                                                 /* calculate the new smoothed ipo's with weighted averages:
2607                                                  *      - this is done with two passes
2608                                                  *      - uses 5 points for each operation (which stores in the relevant handles)
2609                                                  *      -       previous: w/a ratio = 3:5:2:1:1
2610                                                  *      -       next: w/a ratio = 1:1:2:5:3
2611                                                  */
2612                                                 
2613                                                 /* round 1: calculate previous and next */ 
2614                                                 tsb= tarray;
2615                                                 for (i=0; i < totSel; i++, tsb++) {
2616                                                         /* don't touch end points (otherwise, curves slowly explode) */
2617                                                         if (ELEM(i, 0, (totSel-1)) == 0) {
2618                                                                 tSmooth_Bezt *tP1 = tsb - 1;
2619                                                                 tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
2620                                                                 tSmooth_Bezt *tN1 = tsb + 1;
2621                                                                 tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
2622                                                                 
2623                                                                 float p1 = *tP1->h2;
2624                                                                 float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
2625                                                                 float c1 = *tsb->h2;
2626                                                                 float n1 = *tN1->h2;
2627                                                                 float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
2628                                                                 
2629                                                                 /* calculate previous and next */
2630                                                                 *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
2631                                                                 *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
2632                                                         }
2633                                                 }
2634                                                 
2635                                                 /* round 2: calculate new values and reset handles */
2636                                                 tsb= tarray;
2637                                                 for (i=0; i < totSel; i++, tsb++) {
2638                                                         /* calculate new position by averaging handles */
2639                                                         *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
2640                                                         
2641                                                         /* reset handles now */
2642                                                         *tsb->h1 = *tsb->h2;
2643                                                         *tsb->h3 = *tsb->h2;
2644                                                 }
2645                                                 
2646                                                 /* free memory required for tarray */
2647                                                 MEM_freeN(tarray);
2648                                         }
2649                                 }
2650                                 
2651                                 /* recalculate handles */
2652                                 calchandles_ipocurve(icu);
2653                         }
2654                 }
2655         }
2656         
2657         editipo_changed(G.sipo, 1);
2658         BIF_undo_push("Smooth IPO");
2659 }
2660
2661 void join_ipo_menu(void)
2662 {
2663         int mode = 0;
2664         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2665         
2666         if (mode == -1) return;
2667         
2668         join_ipo(mode);
2669 }
2670
2671 void join_ipo(int mode)
2672 {
2673         EditIpo *ei;
2674         IpoKey *ik;
2675         IpoCurve *icu;
2676         BezTriple *bezt, *beztn, *newb;
2677         float val;
2678         int tot, a, b;
2679         
2680         get_status_editipo();
2681         
2682         /* Mode events:
2683          * All Selected: 1
2684          * Selected Doubles: 2
2685          */
2686         
2687         if( mode==2 ) {
2688                 remove_doubles_ipo();
2689                 return;
2690         }
2691         
2692         /* first: multiple selected verts in 1 curve */
2693         ei= G.sipo->editipo;
2694         for(a=0; a<G.sipo->totipo; a++, ei++) {
2695                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2696                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2697                                 icu= ei->icu;
2698                                 
2699                                 /* how many points */
2700                                 tot= 0;
2701                                 b= icu->totvert;
2702                                 bezt= icu->bezt;
2703                                 while(b--) {
2704                                         if(bezt->f2 & SELECT) tot++;
2705                                         bezt++;
2706                                 }
2707                                 
2708                                 if(tot>1) {
2709                                         tot--;
2710                                         icu->totvert-= tot;
2711                                         
2712                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2713                                         /* the first point is the new one */
2714                                         beztn= newb+1;
2715                                         tot= 0;
2716                                         
2717                                         bezt= icu->bezt;
2718                                         b= icu->totvert+tot+1;
2719                                         while(b--) {
2720                                                 
2721                                                 if(bezt->f2 & SELECT) {
2722                                                         if(tot==0) *newb= *bezt;
2723                                                         else {
2724                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2725                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2726                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2727                                                         }
2728                                                         tot++;
2729                                                 }
2730                                                 else {
2731                                                         *beztn= *bezt;
2732                                                         beztn++;
2733                                                 }
2734                                                 bezt++;
2735                                         }
2736                                         
2737                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2738                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2739                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2740                                         
2741                                         MEM_freeN(icu->bezt);
2742                                         icu->bezt= newb;
2743                                         
2744                                         sort_time_ipocurve(icu);
2745                                         calchandles_ipocurve(icu);
2746                                 }
2747                         }
2748                 }
2749         }
2750         
2751         /* next: in keymode: join multiple selected keys */
2752         
2753         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2754         
2755         if(G.sipo->showkey) {
2756                 ik= G.sipo->ipokey.first;
2757                 val= 0.0;
2758                 tot= 0;
2759                 while(ik) {
2760                         if(ik->flag & 1) {
2761                                 for(a=0; a<G.sipo->totipo; a++) {
2762                                         if(ik->data[a]) {
2763                                                 val+= ik->data[a]->vec[1][0];
2764                                                 break;
2765                                         }
2766                                 }
2767                                 tot++;
2768                         }
2769                         ik= ik->next;
2770                 }
2771                 if(tot>1) {
2772                         val/= (float)tot;
2773                         
2774                         ik= G.sipo->ipokey.first;
2775                         while(ik) {
2776                                 if(ik->flag & 1) {
2777                                         for(a=0; a<G.sipo->totipo; a++) {
2778                                                 if(ik->data[a]) {
2779                                                         ik->data[a]->vec[1][0]= val;
2780                                                 }
2781                                         }
2782                                 }
2783                                 ik= ik->next;
2784                         }
2785                         editipo_changed(G.sipo, 0);
2786                 }
2787         }
2788         deselectall_editipo();
2789         BIF_undo_push("Join Ipo");
2790 }
2791
2792 void ipo_snap_menu(void)
2793 {
2794         short event;
2795         
2796         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2797         if(event < 1) return;
2798
2799         ipo_snap(event);
2800 }
2801
2802 void ipo_snap(short event)
2803 {
2804         EditIpo *ei;
2805         BezTriple *bezt;
2806         float dx = 0.0;
2807         int a, b;
2808         short ok, ok2;
2809         
2810         /* events:
2811          * Horizontal : 1
2812          * To Next: 2
2813          * To Frame: 3
2814          * To Current Frame: 4
2815          */
2816          
2817         get_status_editipo();
2818         
2819         /* map ipo-points for editing if scaled ipo */
2820         if (NLA_IPO_SCALED) {
2821                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
2822         }
2823
2824         ei= G.sipo->editipo;
2825         for(b=0; b<G.sipo->totipo; b++, ei++) {
2826                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2827                 
2828                         ok2= 0;
2829                         if(G.sipo->showkey) ok2= 1;
2830                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2831                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2832                         
2833                         if(ok2) {
2834                                 bezt= ei->icu->bezt;
2835                                 a= ei->icu->totvert;
2836                                 while(a--) {
2837                                         ok= 0;
2838                                         if(totipo_vert) {
2839                                                 if(bezt->f2 & SELECT) ok= 1;
2840                                         }
2841                                         else ok= 1;
2842                                         
2843                                         if(ok) {
2844                                                 if(event==1) {
2845                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2846                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2847                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2848                                                 }
2849                                                 else if(event==2) {
2850                                                         if(a) {
2851                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2852                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2853                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2854                                                         }
2855                                                 }
2856                                                 else if(event==3) {
2857                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2858                                                 }
2859                                                 else if(event==4) {     /* to current frame */
2860                                                         
2861                                                         if(ok2==1 || ok2==2) {
2862                                                                 
2863                                                                 if(G.sipo->blocktype==ID_SEQ) {
2864                                                                         Sequence *seq;
2865                                                         
2866                                                                         seq= (Sequence *)G.sipo->from;
2867                                                                         if(seq && (seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
2868                                                             &nb