svn merge -r 16454:16593 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.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                                                 ik->data[a]->f1 |= SELECT;
1350                                                 ik->data[a]->f2 |= SELECT;
1351                                                 ik->data[a]->f3 |= SELECT;
1352                                         }
1353                                         else {
1354                                                 ik->data[a]->f1 &= ~SELECT;
1355                                                 ik->data[a]->f2 &= ~SELECT;
1356                                                 ik->data[a]->f3 &= ~SELECT;
1357                                         }
1358                                 }
1359                         }
1360                         ik= ik->next;
1361                 }
1362         }
1363 }
1364
1365 /* sort of enter/leave editmode for curves */
1366 void set_editflag_editipo(void)
1367 {
1368         EditIpo *ei;
1369         int a; /*  , tot= 0, ok= 0; */
1370         
1371         /* after showkey immediately go to editing of selected points */
1372         if(G.sipo->showkey) {
1373                 G.sipo->showkey= 0;
1374                 if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
1375                 ei= G.sipo->editipo;
1376                 for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
1377                 scrarea_queue_headredraw(curarea);
1378                 allqueue(REDRAWVIEW3D, 0);
1379         }
1380         
1381         get_status_editipo();
1382         
1383         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1384         
1385         ei= G.sipo->editipo;
1386         for(a=0; a<G.sipo->totipo; a++, ei++) {         
1387                 if(ei->icu) {
1388                         if(ei->flag & IPO_VISIBLE) {
1389                                 
1390                                 if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
1391                                         ei->flag |= IPO_EDIT;
1392                                         ei->icu->flag= ei->flag;
1393                                 }
1394                                 else if(totipo_edit && (ei->flag & IPO_EDIT)) {
1395                                         ei->flag -= IPO_EDIT;
1396                                         ei->icu->flag= ei->flag;
1397                                 }
1398                                 else if(totipo_vis==1) {
1399                                         if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
1400                                         else ei->flag |= IPO_EDIT;
1401                                         ei->icu->flag= ei->flag;
1402                                 }
1403                         }
1404                 }
1405         }
1406         scrarea_queue_headredraw(curarea);
1407         scrarea_queue_winredraw(curarea);
1408 }
1409
1410 static short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
1411 {
1412         /* selected verts get a disadvantage */
1413         /* in icu and (bezt or bp) the nearest is written */
1414         /* return 0 1 2: handlepunt */
1415         EditIpo *ei;
1416         BezTriple *bezt1;
1417         int dist= 100, temp, a, b;
1418         short mval[2], hpoint=0, sco[3][2];
1419
1420         *icu= 0;
1421         *bezt= 0;
1422
1423         getmouseco_areawin(mval);
1424
1425         ei= G.sipo->editipo;
1426         for(a=0; a<G.sipo->totipo; a++, ei++) {
1427                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
1428                         
1429                         if(ei->icu->bezt) {
1430                                 bezt1= ei->icu->bezt;
1431                                 b= ei->icu->totvert;
1432                                 while(b--) {
1433
1434                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], sco[0]);
1435                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], sco[1]);
1436                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], sco[2]);
1437                                                                                 
1438                                         if(ei->disptype==IPO_DISPBITS) {
1439                                                 temp= abs(mval[0]- sco[1][0]);
1440                                         }
1441                                         else temp= abs(mval[0]- sco[1][0])+ abs(mval[1]- sco[1][1]);
1442
1443                                         if( bezt1->f2 & SELECT) temp+=5;
1444                                         if(temp<dist) { 
1445                                                 hpoint= 1; 
1446                                                 *bezt= bezt1; 
1447                                                 dist= temp; 
1448                                                 *icu= ei->icu; 
1449                                         }
1450                                         
1451                                         if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
1452                                                 /* middle points get an advantage */
1453                                                 temp= -3+abs(mval[0]- sco[0][0])+ abs(mval[1]- sco[0][1]);
1454                                                 if( bezt1->f1 & 1) temp+=5;
1455                                                 if(temp<dist) { 
1456                                                         hpoint= 0; 
1457                                                         *bezt= bezt1; 
1458                                                         dist= temp; 
1459                                                         *icu= ei->icu; 
1460                                                 }
1461                 
1462                                                 temp= abs(mval[0]- sco[2][0])+ abs(mval[1]- sco[2][1]);
1463                                                 if( bezt1->f3 & 1) temp+=5;
1464                                                 if(temp<dist) { 
1465                                                         hpoint= 2; 
1466                                                         *bezt=bezt1; 
1467                                                         dist= temp; 
1468                                                         *icu= ei->icu; 
1469                                                 }
1470                                         }
1471                                         bezt1++;
1472                                 }
1473                         }
1474                 }
1475         }
1476
1477         return hpoint;
1478 }
1479
1480 void mouse_select_ipo(void)
1481 {
1482         Object *ob;
1483         KeyBlock *actkb=NULL;
1484         EditIpo *ei, *actei= 0;
1485         IpoCurve *icu;
1486         IpoKey *ik, *actik;
1487         BezTriple *bezt;
1488         TimeMarker *marker;
1489         float x, y, dist, mindist;
1490         int a, oldflag = 0, hand, ok;
1491         short mval[2], xo, yo;
1492         
1493         if(G.sipo->editipo==0) return;
1494         
1495         get_status_editipo();
1496         marker=find_nearest_marker(SCE_MARKERS, 1);
1497         
1498         /* map ipo-points for editing if scaled ipo */
1499         if (NLA_IPO_SCALED) {
1500                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
1501         }
1502         
1503         if(G.sipo->showkey) {
1504                 float pixelwidth;
1505                 
1506                 view2d_getscale(G.v2d, &pixelwidth, NULL);
1507                 
1508                 getmouseco_areawin(mval);
1509                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1510                 actik= 0;
1511                 mindist= 1000.0;
1512                 ik= G.sipo->ipokey.first;
1513                 while(ik) {
1514                         dist= (float)(fabs(ik->val-x));
1515                         if(ik->flag & SELECT) dist+= pixelwidth;
1516                         if(dist < mindist) {
1517                                 actik= ik;
1518                                 mindist= dist;
1519                         }
1520                         ik= ik->next;
1521                 }
1522                 if(actik) {
1523                         oldflag= actik->flag;
1524                         
1525                         if(G.qual & LR_SHIFTKEY);
1526                         else deselectall_editipo();
1527                         
1528                         if(G.qual & LR_SHIFTKEY) {
1529                                 if(oldflag & 1) actik->flag &= ~1;
1530                                 else actik->flag |= 1;
1531                         }
1532                         else {
1533                                 actik->flag |= 1;
1534                         }
1535                 }
1536         }
1537         else if(totipo_edit) {
1538                 
1539                 hand= findnearest_ipovert(&icu, &bezt);
1540                 
1541                 if(G.qual & LR_SHIFTKEY) {
1542                         if(bezt) {
1543                                 if(hand==1) {
1544                                         if(BEZSELECTED(bezt)) {
1545                                                 bezt->f1= bezt->f2= bezt->f3= 0;
1546                                         }
1547                                         else {
1548                                                 bezt->f1= bezt->f2= bezt->f3= SELECT;
1549                                         }
1550                                 }
1551                                 else if(hand==0) {
1552                                         if(bezt->f1 & SELECT) bezt->f1= 0;
1553                                         else bezt->f1= SELECT;
1554                                 }
1555                                 else {
1556                                         if(bezt->f3 & SELECT) bezt->f3= 0;
1557                                         else bezt->f3= SELECT;
1558                                 }
1559                         }                               
1560                 }
1561                 else {
1562                         deselectall_editipo();
1563                         
1564                         if(bezt) {
1565                                 if(hand==1) {
1566                                         bezt->f1|= SELECT; bezt->f2|= SELECT; bezt->f3|= SELECT;
1567                                 }
1568                                 else if(hand==0) bezt->f1 |= SELECT;
1569                                 else bezt->f3 |= SELECT;
1570                         }
1571                 }
1572         }
1573         else if (marker) {
1574                 /* select timeline marker */
1575                 if ((G.qual & LR_SHIFTKEY)==0) {
1576                         oldflag= marker->flag;
1577                         deselect_markers(0, 0);
1578                         
1579                         if (oldflag & SELECT)
1580                                 marker->flag &= ~SELECT;
1581                         else
1582                                 marker->flag |= SELECT;
1583                 }
1584                 else {
1585                         marker->flag |= SELECT;                         
1586                 }               
1587         }
1588         else {
1589                 
1590                 /* vertex keys ? */
1591                 if(G.sipo->blocktype==ID_KE && G.sipo->from) {
1592                         Key *key;
1593                         KeyBlock *kb, *curkb;
1594                         int i, index= 1;
1595                         
1596                         ob= (Object *)G.sipo->from;
1597                         key= ob_get_key(ob);
1598                         curkb= BLI_findlink(&key->block, ob->shapenr-1);
1599                         
1600                         ei= G.sipo->editipo;
1601                         if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
1602                                 getmouseco_areawin(mval);
1603                                 
1604                                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1605                                 /* how much is 20 pixels? */
1606                                 mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
1607                                 
1608                                 for(i=1, kb= key->block.first; kb; kb= kb->next, i++) {
1609                                         dist= (float)(fabs(kb->pos-y));
1610                                         if(kb==curkb) dist+= (float)0.01;
1611                                         if(dist < mindist) {
1612                                                 actkb= kb;
1613                                                 mindist= dist;
1614                                                 index= i;
1615                                         }
1616                                 }
1617                                 if(actkb) {
1618                                         ok= TRUE;
1619                                         if(G.obedit && actkb!=curkb) {
1620                                                 ok= okee("Copy key after leaving Edit Mode");
1621                                         }
1622                                         if(ok) {
1623                                                 /* also does all keypos */
1624                                                 deselectall_editipo();
1625                                                 set_active_key(index);
1626                                                 set_active_editipo(ei+index-1);
1627                                         }
1628                                 }
1629                         }
1630                 }
1631                 
1632                 /* select curve */
1633                 if(actkb==NULL) {
1634                         if(totipo_vis==1) {
1635                                 ei= G.sipo->editipo;
1636                                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1637                                         if(ei->icu) {
1638                                                 if(ei->flag & IPO_VISIBLE) actei= ei;
1639                                         }
1640                                 }
1641                         }
1642                         else if(totipo_vis>1) {
1643                                 actei= select_proj_ipo(0, 0);
1644                         }
1645                         
1646                         if(actei) oldflag= actei->flag;
1647                         
1648                         if(G.qual & LR_SHIFTKEY);
1649                         else deselectall_editipo();
1650                         
1651                         if(actei) {
1652                                 if(G.qual & LR_SHIFTKEY) {
1653                                         if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
1654                                         else actei->flag |= IPO_SELECT;
1655                                 }
1656                                 else {
1657                                         actei->flag |= IPO_SELECT;
1658                                 }
1659                                 set_active_editipo(actei);
1660                         }
1661                 }
1662         }
1663         
1664         /* undo mapping of ipo-points for editing if scaled ipo */
1665         if (NLA_IPO_SCALED) {
1666                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
1667         }
1668         
1669         update_editipo_flags();
1670         
1671         force_draw(0);
1672         BIF_undo_push("Select Ipo");
1673         
1674         if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
1675                 ob= OBACT;
1676                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
1677         }
1678         /* points inside of curve are drawn selected too */
1679         if(G.sipo->blocktype==ID_CU)
1680                 allqueue(REDRAWVIEW3D, 0);
1681         
1682         getmouseco_areawin(mval);
1683         xo= mval[0]; 
1684         yo= mval[1];
1685         
1686         while (get_mbut() & ((U.flag & USER_LMOUSESELECT)?L_MOUSE:R_MOUSE)) {           
1687                 getmouseco_areawin(mval);
1688                 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
1689                         
1690                         if (marker) {
1691                                 transform_markers('g', 0);
1692                         }
1693                         else {
1694                                 if(actkb) move_keys(OBACT);
1695                                 else transform_ipo('g');
1696                         }
1697                         
1698                         return;
1699                 }
1700                 BIF_wait_for_statechange();
1701         }
1702 }
1703
1704
1705 /* *********************************** */
1706
1707 /* handling of right-hand channel/curve buttons in ipo window */
1708 void do_ipowin_buts(short event)
1709 {
1710         EditIpo *ei = NULL;
1711         int a;
1712
1713         /* without shift, all other channels are made invisible */
1714         if((G.qual & LR_SHIFTKEY)==0) {
1715                 if(event>G.sipo->totipo) return;
1716                 ei = G.sipo->editipo;
1717                 for(a=0; a<G.sipo->totipo; a++) {
1718                         if(a!=event) ei->flag &= ~IPO_VISIBLE;
1719                         else ei->flag |= IPO_VISIBLE;
1720                         ei++;
1721                 }
1722         }
1723         
1724         /* set active */
1725         if(event>=0 && event<G.sipo->totipo) {
1726                 ei= G.sipo->editipo;    // void pointer...
1727                 set_active_editipo(ei+event);
1728                 set_active_key(event+1);        // only if there's a key, of course
1729         }
1730         scrarea_queue_winredraw(curarea);
1731         
1732         update_editipo_flags();
1733         get_status_editipo();
1734
1735         if(G.sipo->showkey) {
1736                 make_ipokey();
1737                 if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
1738         }
1739
1740 }
1741
1742 /* the fake buttons to the left of channel names, for select/deselect curves */
1743 void do_ipo_selectbuttons(void)
1744 {
1745         EditIpo *ei, *ei1;
1746         int a, nr;
1747         short mval[2];
1748         
1749         if(G.sipo->showkey) return;
1750         
1751         /* do not allow editipo here: convert editipos to selected */
1752         get_status_editipo();
1753         if(totipo_edit) {
1754                 set_editflag_editipo();
1755         }
1756         
1757         /* which */
1758         getmouseco_areawin(mval);
1759
1760         nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
1761         if(G.sipo->blocktype==ID_KE) nr--;              /* keys show something else in first channel */
1762         
1763         if(nr>=0 && nr<G.sipo->totipo) {
1764                 ei= G.sipo->editipo;
1765                 ei+= nr;
1766                 
1767                 set_active_editipo(ei);
1768                 set_active_key(nr+1);
1769
1770                 if(ei->icu) {
1771                         if((ei->flag & IPO_VISIBLE)==0) {
1772                                 ei->flag |= IPO_VISIBLE|IPO_SELECT;
1773                         }
1774         
1775                         if((G.qual & LR_SHIFTKEY)==0) {
1776                                 ei1= G.sipo->editipo;
1777                                 for(a=0; a<G.sipo->totipo; a++) {
1778                                         ei1->flag &= ~IPO_SELECT;
1779                                         ei1++;
1780                                 }
1781                         }
1782
1783                         if(ei->flag & IPO_SELECT) {
1784                                 ei->flag &= ~IPO_SELECT;
1785                         }
1786                         else {
1787                                 ei->flag |= IPO_SELECT;
1788                         }
1789                         
1790                         update_editipo_flags();
1791                         scrarea_queue_winredraw(curarea);
1792                 }
1793         }
1794         BIF_undo_push("Select Ipo curve");
1795 }
1796
1797 /* ********************************* Inserting keys ********************************************* */
1798
1799 /* depending type, it returns ipo, if needed it creates one */
1800 /* returns either action ipo or "real" ipo */
1801 /* arguments define full context;
1802    - *from has to be set always, to Object in case of Actions
1803    - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too)
1804    - if actname, use this to locate actionchannel, and optional constname 
1805    - if bonename, the constname is the ipo to the constraint
1806 */
1807
1808 /* note: check header_ipo.c, spaceipo_assign_ipo() too */
1809 Ipo *verify_ipo(ID *from, short blocktype, char *actname, char *constname, char *bonename, short add)
1810 {
1811         /* lib-linked data is not appropriate here */
1812         if ((from==NULL) || (from->lib))
1813                 return NULL;
1814         
1815         /* first check action ipos */
1816         if (actname && actname[0]) {
1817                 Object *ob= (Object *)from;
1818                 bActionChannel *achan;
1819                 
1820                 if (GS(from->name)!=ID_OB) {
1821                         printf("called ipo system for action with wrong base pointer\n");
1822                         return NULL;
1823                 }
1824                 
1825                 if ((ob->action==NULL) && (add))
1826                         ob->action= add_empty_action("Action");
1827                 
1828                 if (add)
1829                         achan= verify_action_channel(ob->action, actname);
1830                 else    
1831                         achan= get_action_channel(ob->action, actname);
1832                 
1833                 if (achan) {
1834                         /* automatically assign achan to act-group based on pchan's grouping */
1835                         if ((blocktype == ID_PO) && (add))
1836                                 verify_pchan2achan_grouping(ob->action, ob->pose, actname);
1837                         
1838                         /* constraint exception */
1839                         if (blocktype==ID_CO) {
1840                                 bConstraintChannel *conchan;
1841                                 
1842                                 if (add)
1843                                         conchan= verify_constraint_channel(&achan->constraintChannels, constname);
1844                                 else
1845                                         conchan= get_constraint_channel(&achan->constraintChannels, constname);
1846                                         
1847                                 if (conchan) {
1848                                         if ((conchan->ipo==NULL) && (add))
1849                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1850                                         return conchan->ipo;
1851                                 }
1852                         }
1853                         else {
1854                                 if ((achan->ipo==NULL) && (add))
1855                                         achan->ipo= add_ipo("ActIpo", blocktype);
1856                                 return achan->ipo;
1857                         }
1858                 }
1859         }
1860         else {
1861                 switch (GS(from->name)) {
1862                 case ID_OB:
1863                         {
1864                                 Object *ob= (Object *)from;
1865                                 
1866                                 /* constraint exception */
1867                                 if (blocktype==ID_CO) {
1868                                         /* check the local constraint ipo */
1869                                         if (bonename && bonename[0] && ob->pose) {
1870                                                 bPoseChannel *pchan= get_pose_channel(ob->pose, bonename);
1871                                                 bConstraint *con;
1872                                                 
1873                                                 for (con= pchan->constraints.first; con; con= con->next) {
1874                                                         if (strcmp(con->name, constname)==0)
1875                                                                 break;
1876                                                 }
1877                                                 
1878                                                 if (con) {
1879                                                         if ((con->ipo==NULL) && (add))
1880                                                                 con->ipo= add_ipo("CoIpo", ID_CO);
1881                                                         return con->ipo;
1882                                                 }
1883                                         }
1884                                         else { /* the actionchannel */
1885                                                 bConstraintChannel *conchan;
1886                                                 
1887                                                 if (add)
1888                                                         conchan= verify_constraint_channel(&ob->constraintChannels, constname);
1889                                                 else
1890                                                         conchan= get_constraint_channel(&ob->constraintChannels, constname);
1891                                                         
1892                                                 if (conchan) {
1893                                                         if ((conchan->ipo==NULL) && (add))
1894                                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1895                                                         return conchan->ipo;
1896                                                 }
1897                                         }
1898                                 }
1899                                 else if (blocktype==ID_OB) {
1900                                         if ((ob->ipo==NULL) && (add))
1901                                                 ob->ipo= add_ipo("ObIpo", ID_OB);
1902                                         return ob->ipo;
1903                                 }
1904                                 else if (blocktype==ID_KE) {
1905                                         Key *key= ob_get_key((Object *)from);
1906                                         
1907                                         if (key) {
1908                                                 if ((key->ipo==NULL) && (add))
1909                                                         key->ipo= add_ipo("KeyIpo", ID_KE);
1910                                                 return key->ipo;
1911                                         }
1912                                         return NULL;
1913                                 }
1914                                 else if (blocktype== ID_FLUIDSIM) {
1915                                         Object *ob= (Object *)from;
1916
1917                                         FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
1918                                         if(fluidmd) {
1919                                                 FluidsimSettings *fss= fluidmd->fss;
1920                                                 
1921                                                 if ((fss->ipo==NULL) && (add))
1922                                                         fss->ipo= add_ipo("FluidsimIpo", ID_FLUIDSIM);
1923                                                 return fss->ipo;
1924                                         }
1925                                 }
1926                                 else if(blocktype== ID_PA) {
1927                                         Object *ob= (Object *)from;
1928                                         ParticleSystem *psys= psys_get_current(ob);
1929                                         
1930                                         if (psys) {
1931                                                 if ((psys->part->ipo==NULL) && (add))
1932                                                         psys->part->ipo= add_ipo("ParticleIpo", ID_PA);
1933                                                 return psys->part->ipo;
1934                                         }
1935                                         return NULL;
1936                                 }
1937                         }
1938                         break;
1939                 case ID_MA:
1940                         {
1941                                 Material *ma= (Material *)from;
1942                                 
1943                                 if ((ma->ipo==NULL) && (add))
1944                                         ma->ipo= add_ipo("MatIpo", ID_MA);
1945                                 return ma->ipo;
1946                         }
1947                         break;
1948                 case ID_TE:
1949                         {
1950                                 Tex *tex= (Tex *)from;
1951                                 
1952                                 if ((tex->ipo==NULL) && (add))
1953                                         tex->ipo= add_ipo("TexIpo", ID_TE);
1954                                 return tex->ipo;
1955                         }
1956                         break;
1957                 case ID_SEQ:
1958                         {
1959                                 Sequence *seq= (Sequence *)from;        /* note, sequence is mimicing Id */
1960                                 
1961                                 if ((seq->ipo==NULL) && (add))
1962                                         seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1963                                 update_seq_ipo_rect(seq);
1964                                 return seq->ipo;
1965                         }
1966                         break;
1967                 case ID_CU:
1968                         {
1969                                 Curve *cu= (Curve *)from;
1970                                 
1971                                 if ((cu->ipo==NULL) && (add))
1972                                         cu->ipo= add_ipo("CuIpo", ID_CU);
1973                                 return cu->ipo;
1974                         }
1975                         break;
1976                 case ID_WO:
1977                         {
1978                                 World *wo= (World *)from;
1979                                 
1980                                 if ((wo->ipo==NULL) && (add))
1981                                         wo->ipo= add_ipo("WoIpo", ID_WO);
1982                                 return wo->ipo;
1983                         }
1984                         break;
1985                 case ID_LA:
1986                         {
1987                                 Lamp *la= (Lamp *)from;
1988                                 
1989                                 if ((la->ipo==NULL) && (add))
1990                                         la->ipo= add_ipo("LaIpo", ID_LA);
1991                                 return la->ipo;
1992                         }
1993                         break;
1994                 case ID_CA:
1995                         {
1996                                 Camera *ca= (Camera *)from;
1997                                 
1998                                 if ((ca->ipo==NULL) && (add))
1999                                         ca->ipo= add_ipo("CaIpo", ID_CA);
2000                                 return ca->ipo;
2001                         }
2002                         break;
2003                 case ID_SO:
2004                         {
2005                                 bSound *snd= (bSound *)from;
2006                                 
2007                                 if ((snd->ipo==NULL) && (add))
2008                                         snd->ipo= add_ipo("SndIpo", ID_SO);
2009                                 return snd->ipo;
2010                         }
2011                 }
2012         }
2013         
2014         return NULL;    
2015 }
2016
2017 /* returns and creates
2018  * Make sure functions check for NULL or they will crash!
2019  *  */
2020 IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, char *bonename, int adrcode, short add)
2021 {
2022         Ipo *ipo;
2023         IpoCurve *icu= NULL;
2024         
2025         /* return 0 if lib */
2026         /* creates ipo too (if add) */
2027         ipo= verify_ipo(from, blocktype, actname, constname, bonename, add);
2028         
2029         if (ipo && ipo->id.lib==NULL && from->lib==NULL) {
2030                 /* try to find matching curve */
2031                 for (icu= ipo->curve.first; icu; icu= icu->next) {
2032                         if (icu->adrcode==adrcode) 
2033                                 break;
2034                 }
2035                 
2036                 /* make a new one if none found (and can add) */
2037                 if ((icu==NULL) && (add)) {
2038                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
2039                         
2040                         icu->flag |= (IPO_VISIBLE|IPO_AUTO_HORIZ);
2041                         if (ipo->curve.first==NULL) 
2042                                 icu->flag |= IPO_ACTIVE;        /* first one added active */
2043                         
2044                         icu->blocktype= blocktype;
2045                         icu->adrcode= adrcode;
2046                         
2047                         set_icu_vars(icu);
2048                         
2049                         BLI_addtail(&ipo->curve, icu);
2050                         
2051                         switch (GS(from->name)) {
2052                                 case ID_SEQ: {
2053                                         Sequence *seq= (Sequence *)from;
2054                                         
2055                                         update_seq_icu_rects(seq);
2056                                         break;
2057                                 }
2058                         }
2059                 }
2060         }
2061         
2062         /* return ipo-curve */
2063         return icu;
2064 }
2065
2066
2067 void add_vert_ipo(void)
2068 {
2069         EditIpo *ei;
2070         float x, y;
2071         int val;
2072         short mval[2];
2073
2074         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2075         if(G.sipo->showkey) {
2076                 G.sipo->showkey= 0;
2077                 free_ipokey(&G.sipo->ipokey);
2078         }
2079         
2080         getmouseco_areawin(mval);
2081         
2082         if(mval[0]>G.v2d->mask.xmax) return;
2083         
2084         ei= get_active_editipo();
2085         if(ei==NULL) {
2086                 error("No active Ipo curve");
2087                 return;
2088         }
2089         ei->flag |= IPO_VISIBLE;        /* can happen it is active but not visible */
2090         
2091         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
2092         
2093         /* convert click-time to ipo-time */
2094         if (NLA_IPO_SCALED) {
2095                 x= get_action_frame(OBACT, x);
2096         }
2097         
2098         if(ei->icu==NULL) {
2099                 if(G.sipo->from) {
2100                         ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, G.sipo->bonename, ei->adrcode, 1);
2101                         if (ei->icu)
2102                                 ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ;     /* new curve could have been added, weak... */
2103                         else
2104                                 error("Cannot create an IPO curve, you may be using libdata");
2105                 }
2106         }
2107         if(ei->icu==NULL) return;
2108
2109         if(ei->disptype==IPO_DISPBITS) {
2110                 ei->icu->vartype= IPO_BITS;
2111                 val= (int)floor(y-0.5);
2112                 if(val<0) val= 0;
2113                 y= (float)(1 << val);
2114         }
2115         
2116         insert_vert_icu(ei->icu, x, y, 0);
2117
2118         /* to be sure: if icu was 0, or only 1 curve visible */
2119         ei->flag |= IPO_SELECT;
2120         ei->icu->flag= ei->flag;
2121         
2122         editipo_changed(G.sipo, 1);
2123         BIF_undo_push("Add Ipo vertex");
2124 }
2125
2126
2127 void insertkey_editipo(void)
2128 {
2129         EditIpo *ei;
2130         IpoKey *ik;
2131         ID *id;
2132         float *fp, cfra, *insertvals;
2133         int a, nr, ok, tot;
2134         short event;
2135         
2136         ei= get_active_editipo();
2137         if(ei && ei->icu && ei->icu->driver) 
2138                 event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
2139         else if(G.sipo->showkey)
2140                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
2141         else 
2142                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
2143         
2144         if(event<1) return;
2145         
2146         if(event==3) {
2147                 IpoDriver *driver= ei->icu->driver;
2148                 
2149                 if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
2150                 ei->icu->totvert= 0;
2151                 ei->icu->bezt= NULL;
2152                 
2153                 insert_vert_icu(ei->icu, 0.0f, 0.0f, 0);
2154                 
2155                 if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
2156                         if(ei->disptype==IPO_DISPDEGR)
2157                                 insert_vert_icu(ei->icu, 18.0f, 18.0f, 0);
2158                         else
2159                                 insert_vert_icu(ei->icu, 18.0f, 1.0f, 0);
2160                 }
2161                 else
2162                         insert_vert_icu(ei->icu, 1.0f, 1.0f, 0);
2163                 
2164                 ei->flag |= IPO_SELECT|IPO_VISIBLE;
2165                 ei->icu->flag= ei->flag;
2166                 ei->icu->extrap= IPO_DIR;
2167
2168                 do_ipo_buttons(B_IPOHOME);
2169         }
2170         else {
2171                 ei= G.sipo->editipo;
2172                 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
2173                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2174                         
2175                                 ok= 0;
2176                                 if(G.sipo->showkey) ok= 1;
2177                                 else if(ei->flag & IPO_SELECT) ok= 1;
2178
2179                                 if(ok) {
2180                                         /* count amount */
2181                                         if(event==1) tot= 1;
2182                                         else {
2183                                                 ik= G.sipo->ipokey.first;
2184                                                 tot= 0;
2185                                                 while(ik) {
2186                                                         if(ik->flag & 1) tot++;
2187                                                         ik= ik->next;
2188                                                 }
2189                                         }
2190                                         if(tot) {
2191                                         
2192                                                 /* correction for ob timeoffs */
2193                                                 cfra= frame_to_float(CFRA);
2194                                                 id= G.sipo->from;       
2195                                                 if(id && GS(id->name)==ID_OB ) {
2196                                                         Object *ob= (Object *)id;
2197                                                         if((ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0) ) {
2198                                                                 cfra-= give_timeoffset(ob)*G.scene->r.framelen;
2199                                                         }
2200                                                 }
2201                                                 else if(id && GS(id->name)==ID_SEQ) {
2202                                                         Sequence *last_seq = get_last_seq();    /* editsequence.c */
2203                                                         
2204                                                         if(last_seq && (last_seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
2205                                                                 cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
2206                                                         }
2207                                                 }
2208                                                 
2209                                                 /* convert cfra to ipo-time */
2210                                                 if (NLA_IPO_SCALED) {
2211                                                         cfra= get_action_frame(OBACT, cfra);
2212                                                 }
2213                                 
2214                                                 insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
2215                                                 /* make sure icu->curval is correct */
2216                                                 calc_ipo(G.sipo->ipo, cfra);
2217                                                 
2218                                                 if(event==1) {
2219                                                         insertvals[0]= cfra;
2220                                                         
2221                                                         insertvals[1]= ei->icu->curval;
2222                                                 }
2223                                                 else {
2224                                                         fp= insertvals;
2225                                                         ik= G.sipo->ipokey.first;
2226                                                         while(ik) {
2227                                                                 if(ik->flag & 1) {
2228                                                                         calc_ipo(G.sipo->ipo, ik->val);
2229
2230                                                                         fp[0]= ik->val;
2231                                                                         fp[1]= ei->icu->curval;
2232                                                                         fp+= 2;
2233                                                                 }
2234                                                                 ik= ik->next;
2235                                                         }
2236                                                 }
2237                                                 fp= insertvals;
2238                                                 for(a=0; a<tot; a++, fp+=2) {
2239                                                         insert_vert_icu(ei->icu, fp[0], fp[1], 0);
2240                                                 }
2241                                                 
2242                                                 MEM_freeN(insertvals);
2243                                                 calc_ipo(G.sipo->ipo, (float)CFRA);
2244                                         }
2245                                 }
2246                         }
2247                 }
2248         }
2249         BIF_undo_push("Insert Key Ipo");
2250         allqueue (REDRAWACTION, 0);
2251         allqueue(REDRAWNLA, 0);
2252         allqueue(REDRAWIPO, 0);
2253         allspace(REMAKEIPO, 0);
2254 }
2255
2256
2257 /* ****************************************************************************** */
2258
2259 void add_duplicate_editipo(void)
2260 {
2261         Object *ob;
2262         EditIpo *ei;
2263         IpoCurve *icu;
2264         BezTriple *bezt, *beztn, *newb;
2265         int tot, a, b;
2266         
2267         get_status_editipo();
2268         if(totipo_vertsel==0) return;
2269         
2270         ei= G.sipo->editipo;
2271         for(a=0; a<G.sipo->totipo; a++, ei++) {
2272                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2273                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2274                                 icu= ei->icu;
2275                                 
2276                                 /* how many points */
2277                                 tot= 0;
2278                                 b= icu->totvert;
2279                                 bezt= icu->bezt;
2280                                 while(b--) {
2281                                         if(bezt->f2 & SELECT) tot++;
2282                                         bezt++;
2283                                 }
2284                                 
2285                                 if(tot) {
2286                                         icu->totvert+= tot;
2287                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2288                                         bezt= icu->bezt;
2289                                         b= icu->totvert-tot;
2290                                         while(b--) {
2291                                                 *beztn= *bezt;
2292                                                 if(bezt->f2 & SELECT) {
2293                                                         beztn->f1= beztn->f2= beztn->f3= 0;
2294                                                         beztn++;
2295                                                         *beztn= *bezt;
2296                                                 }
2297                                                 beztn++;
2298                                                 bezt++;
2299                                         }
2300                                         MEM_freeN(icu->bezt);
2301                                         icu->bezt= newb;
2302                                         
2303                                         calchandles_ipocurve(icu);
2304                                 }
2305                         }
2306                 }
2307         }
2308         
2309         if(G.sipo->showkey) {
2310                 make_ipokey();
2311                 if(G.sipo->blocktype==ID_OB) {
2312                         ob= OBACT;
2313                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2314                 }
2315         }
2316         BIF_undo_push("Duplicate Ipo");
2317         transform_ipo('g');
2318 }
2319
2320 void remove_doubles_ipo(void)
2321 {
2322         EditIpo *ei;
2323         IpoKey *ik, *ikn;
2324         BezTriple *bezt, *newb, *new1;
2325         float val;
2326         int mode, a, b;
2327         
2328         ei= G.sipo->editipo;
2329         for(a=0; a<G.sipo->totipo; a++, ei++) {
2330                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2331                         
2332                         /* OR the curve is selected OR in editmode OR in keymode */
2333                         mode= 0;
2334                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2335                         else if(ei->flag & IPO_SELECT) mode= 2;
2336                         
2337                         if(mode) {
2338                                 bezt= ei->icu->bezt;
2339                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2340                                 *newb= *bezt;
2341                                 b= ei->icu->totvert-1;
2342                                 bezt++;
2343                                 while(b--) {
2344                                         
2345                                         /* can we remove? */
2346                                         if(mode==2 || (bezt->f2 & SELECT)) {
2347                                         
2348                                                 /* are the points different? */
2349                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2350                                                         newb++;
2351                                                         *newb= *bezt;
2352                                                 }
2353                                                 else {
2354                                                         /* median */
2355                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2356                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2357                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2358                                                         
2359                                                         newb->h1= newb->h2= HD_FREE;
2360                                                         
2361                                                         ei->icu->totvert--;
2362                                                 }
2363                                                 
2364                                         }
2365                                         else {
2366                                                 newb++;
2367                                                 *newb= *bezt;
2368                                         }
2369                                         bezt++;
2370                                 }
2371                                 
2372                                 MEM_freeN(ei->icu->bezt);
2373                                 ei->icu->bezt= new1;
2374                                 
2375                                 calchandles_ipocurve(ei->icu);                          
2376                         }
2377                 }
2378         }
2379         
2380         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2381
2382         /* remove double keys */
2383         if(G.sipo->showkey) {
2384                 ik= G.sipo->ipokey.first;
2385                 ikn= ik->next;
2386                 
2387                 while(ik && ikn) {
2388                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2389                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2390                                         val= (float)((ik->val + ikn->val)/2.0);
2391                                         
2392                                         for(a=0; a<G.sipo->totipo; a++) {
2393                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2394                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2395                                         }
2396                                 }
2397                         }
2398                         ik= ikn;
2399                         ikn= ikn->next;
2400
2401                 }
2402                 
2403                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2404
2405         }
2406         deselectall_editipo();
2407         BIF_undo_push("Remove Doubles (IPO)");
2408 }
2409
2410
2411 void clean_ipo(void) 
2412 {
2413         EditIpo *ei;
2414         short ok;
2415         int b;
2416         
2417         ok= fbutton(&G.scene->toolsettings->clean_thresh, 
2418                                 0.0000001f, 1.0, 0.001, 0.1,
2419                                 "Threshold");
2420         if (!ok) return;
2421         
2422         get_status_editipo();
2423
2424         ei= G.sipo->editipo;
2425         for(b=0; b<G.sipo->totipo; b++, ei++) {
2426                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2427                 
2428                         ok= 0;
2429                         if(G.sipo->showkey) ok= 1;
2430                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
2431                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
2432                         
2433                         if(ok) {
2434                                 /* only clean if ok */
2435                                 clean_ipo_curve(ei->icu);
2436                         }
2437                 }
2438         }
2439         
2440         editipo_changed(G.sipo, 1);
2441         BIF_undo_push("Clean IPO");
2442 }
2443
2444 void clean_ipo_curve(IpoCurve *icu)
2445 {
2446         BezTriple *old_bezts, *bezt, *beztn;
2447         BezTriple *lastb;
2448         int totCount, i;
2449         float thresh;
2450         
2451         /* check if any points  */
2452         if (icu == NULL || icu->totvert <= 1) 
2453                 return;
2454         
2455         /* get threshold for match-testing */
2456         thresh= G.scene->toolsettings->clean_thresh;
2457         
2458         /* make a copy of the old BezTriples, and clear IPO curve */
2459         old_bezts = icu->bezt;
2460         totCount = icu->totvert;        
2461         icu->bezt = NULL;
2462         icu->totvert = 0;
2463         
2464         /* now insert first keyframe, as it should be ok */
2465         bezt = old_bezts;
2466         insert_vert_icu(icu, bezt->vec[1][0], bezt->vec[1][1], 0);
2467         
2468         /* Loop through BezTriples, comparing them. Skip any that do 
2469          * not fit the criteria for "ok" points.
2470          */
2471         for (i=1; i<totCount; i++) {    
2472                 float prev[2], cur[2], next[2];
2473                 
2474                 /* get BezTriples and their values */
2475                 if (i < (totCount - 1)) {
2476                         beztn = (old_bezts + (i+1));
2477                         next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
2478                 }
2479                 else {
2480                         beztn = NULL;
2481                         next[0] = next[1] = 0.0f;
2482                 }
2483                 lastb= (icu->bezt + (icu->totvert - 1));
2484                 bezt= (old_bezts + i);
2485                 
2486                 /* get references for quicker access */
2487                 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
2488                 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
2489                 
2490                 /* check if current bezt occurs at same time as last ok */
2491                 if (IS_EQT(cur[0], prev[0], thresh)) {
2492                         /* If there is a next beztriple, and if occurs at the same time, only insert 
2493                          * if there is a considerable distance between the points, and also if the 
2494                          * current is further away than the next one is to the previous.
2495                          */
2496                         if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 
2497                                 (IS_EQT(next[1], prev[1], thresh)==0)) 
2498                         {
2499                                 /* only add if current is further away from previous */
2500                                 if (cur[1] > next[1]) {
2501                                         if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2502                                                 /* add new keyframe */
2503                                                 insert_vert_icu(icu, cur[0], cur[1], 0);
2504                                         }
2505                                 }
2506                         }
2507                         else {
2508                                 /* only add if values are a considerable distance apart */
2509                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2510                                         /* add new keyframe */
2511                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2512                                 }
2513                         }
2514                 }
2515                 else {
2516                         /* checks required are dependent on whether this is last keyframe or not */
2517                         if (beztn) {
2518                                 /* does current have same value as previous and next? */
2519                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2520                                         /* add new keyframe*/
2521                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2522                                 }
2523                                 else if (IS_EQT(cur[1], next[1], thresh) == 0) {
2524                                         /* add new keyframe */
2525                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2526                                 }
2527                         }
2528                         else {  
2529                                 /* add if value doesn't equal that of previous */
2530                                 if (IS_EQT(cur[1], prev[1], thresh) == 0) {
2531                                         /* add new keyframe */
2532                                         insert_vert_icu(icu, cur[0], cur[1], 0);
2533                                 }
2534                         }
2535                 }
2536         }
2537         
2538         /* now free the memory used by the old BezTriples */
2539         if (old_bezts)
2540                 MEM_freeN(old_bezts);
2541 }
2542
2543
2544 /* temp struct used for smooth_ipo */
2545 typedef struct tSmooth_Bezt {
2546         float *h1, *h2, *h3;    /* bezt->vec[0,1,2][1] */
2547 } tSmooth_Bezt;
2548
2549 void smooth_ipo(void)
2550 {
2551         EditIpo *ei;
2552         short ok;
2553         int b;
2554         
2555         get_status_editipo();
2556
2557         ei= G.sipo->editipo;
2558         for(b=0; b<G.sipo->totipo; b++, ei++) {
2559                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2560                         ok= 0;
2561                         if(G.sipo->showkey) ok= 1;
2562                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
2563                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
2564                         
2565                         if(ok) {
2566                                 IpoCurve *icu= ei->icu;
2567                                 BezTriple *bezt;
2568                                 int i, x, totSel = 0;
2569                                 
2570                                 /* check if enough points */
2571                                 if (icu->totvert >= 3) {
2572                                         /* first loop through - count how many verts are selected, and fix up handles */
2573                                         bezt= icu->bezt;
2574                                         for (i=0; i < icu->totvert; i++, bezt++) {                                              
2575                                                 if (BEZSELECTED(bezt)) {                                                        
2576                                                         /* line point's handles up with point's vertical position */
2577                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2578                                                         if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
2579                                                         if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
2580                                                         
2581                                                         /* add value to total */
2582                                                         totSel++;
2583                                                 }
2584                                         }
2585                                         
2586                                         /* if any points were selected, allocate tSmooth_Bezt points to work on */
2587                                         if (totSel >= 3) {
2588                                                 tSmooth_Bezt *tarray, *tsb;
2589                                                 
2590                                                 /* allocate memory in one go */
2591                                                 tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
2592                                                 
2593                                                 /* populate tarray with data of selected points */
2594                                                 bezt= icu->bezt;
2595                                                 for (i=0, x=0; (i < icu->totvert) && (x < totSel); i++, bezt++) {
2596                                                         if (BEZSELECTED(bezt)) {
2597                                                                 /* tsb simply needs pointer to vec, and index */
2598                                                                 tsb->h1 = &bezt->vec[0][1];
2599                                                                 tsb->h2 = &bezt->vec[1][1];
2600                                                                 tsb->h3 = &bezt->vec[2][1];
2601                                                                 
2602                                                                 /* advance to the next tsb to populate */
2603                                                                 if (x < totSel- 1) 
2604                                                                         tsb++;
2605                                                                 else
2606                                                                         break;
2607                                                         }
2608                                                 }
2609                                                 
2610                                                 /* calculate the new smoothed ipo's with weighted averages:
2611                                                  *      - this is done with two passes
2612                                                  *      - uses 5 points for each operation (which stores in the relevant handles)
2613                                                  *      -       previous: w/a ratio = 3:5:2:1:1
2614                                                  *      -       next: w/a ratio = 1:1:2:5:3
2615                                                  */
2616                                                 
2617                                                 /* round 1: calculate previous and next */ 
2618                                                 tsb= tarray;
2619                                                 for (i=0; i < totSel; i++, tsb++) {
2620                                                         /* don't touch end points (otherwise, curves slowly explode) */
2621                                                         if (ELEM(i, 0, (totSel-1)) == 0) {
2622                                                                 tSmooth_Bezt *tP1 = tsb - 1;
2623                                                                 tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
2624                                                                 tSmooth_Bezt *tN1 = tsb + 1;
2625                                                                 tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
2626                                                                 
2627                                                                 float p1 = *tP1->h2;
2628                                                                 float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
2629                                                                 float c1 = *tsb->h2;
2630                                                                 float n1 = *tN1->h2;
2631                                                                 float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
2632                                                                 
2633                                                                 /* calculate previous and next */
2634                                                                 *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
2635                                                                 *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
2636                                                         }
2637                                                 }
2638                                                 
2639                                                 /* round 2: calculate new values and reset handles */
2640                                                 tsb= tarray;
2641                                                 for (i=0; i < totSel; i++, tsb++) {
2642                                                         /* calculate new position by averaging handles */
2643                                                         *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
2644                                                         
2645                                                         /* reset handles now */
2646                                                         *tsb->h1 = *tsb->h2;
2647                                                         *tsb->h3 = *tsb->h2;
2648                                                 }
2649                                                 
2650                                                 /* free memory required for tarray */
2651                                                 MEM_freeN(tarray);
2652                                         }
2653                                 }
2654                                 
2655                                 /* recalculate handles */
2656                                 calchandles_ipocurve(icu);
2657                         }
2658                 }
2659         }
2660         
2661         editipo_changed(G.sipo, 1);
2662         BIF_undo_push("Smooth IPO");
2663 }
2664
2665 void join_ipo_menu(void)
2666 {
2667         int mode = 0;
2668         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2669         
2670         if (mode == -1) return;
2671         
2672         join_ipo(mode);
2673 }
2674
2675 void join_ipo(int mode)
2676 {
2677         EditIpo *ei;
2678         IpoKey *ik;
2679         IpoCurve *icu;
2680         BezTriple *bezt, *beztn, *newb;
2681         float val;
2682         int tot, a, b;
2683         
2684         get_status_editipo();
2685         
2686         /* Mode events:
2687          * All Selected: 1
2688          * Selected Doubles: 2
2689          */
2690         
2691         if( mode==2 ) {
2692                 remove_doubles_ipo();
2693                 return;
2694         }
2695         
2696         /* first: multiple selected verts in 1 curve */
2697         ei= G.sipo->editipo;
2698         for(a=0; a<G.sipo->totipo; a++, ei++) {
2699                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2700                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2701                                 icu= ei->icu;
2702                                 
2703                                 /* how many points */
2704                                 tot= 0;
2705                                 b= icu->totvert;
2706                                 bezt= icu->bezt;
2707                                 while(b--) {
2708                                         if(bezt->f2 & SELECT) tot++;
2709                                         bezt++;
2710                                 }
2711                                 
2712                                 if(tot>1) {
2713                                         tot--;
2714                                         icu->totvert-= tot;
2715                                         
2716                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2717                                         /* the first point is the new one */
2718                                         beztn= newb+1;
2719                                         tot= 0;
2720                                         
2721                                         bezt= icu->bezt;
2722                                         b= icu->totvert+tot+1;
2723                                         while(b--) {
2724                                                 
2725                                                 if(bezt->f2 & SELECT) {
2726                                                         if(tot==0) *newb= *bezt;
2727                                                         else {
2728                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2729                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2730                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2731                                                         }
2732                                                         tot++;
2733                                                 }
2734                                                 else {
2735                                                         *beztn= *bezt;
2736                                                         beztn++;
2737                                                 }
2738                                                 bezt++;
2739                                         }
2740                                         
2741                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2742                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2743                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2744                                         
2745                                         MEM_freeN(icu->bezt);
2746                                         icu->bezt= newb;
2747                                         
2748                                         sort_time_ipocurve(icu);
2749                                         calchandles_ipocurve(icu);
2750                                 }
2751                         }
2752                 }
2753         }
2754         
2755         /* next: in keymode: join multiple selected keys */
2756         
2757         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2758         
2759         if(G.sipo->showkey) {
2760                 ik= G.sipo->ipokey.first;
2761                 val= 0.0;
2762                 tot= 0;
2763                 while(ik) {
2764                         if(ik->flag & 1) {
2765                                 for(a=0; a<G.sipo->totipo; a++) {
2766                                         if(ik->data[a]) {
2767                                                 val+= ik->data[a]->vec[1][0];
2768                                                 break;
2769                                         }
2770                                 }
2771                                 tot++;
2772                         }
2773                         ik= ik->next;
2774                 }
2775                 if(tot>1) {
2776                         val/= (float)tot;
2777                         
2778                         ik= G.sipo->ipokey.first;
2779                         while(ik) {
2780                                 if(ik->flag & 1) {
2781                                         for(a=0; a<G.sipo->totipo; a++) {
2782                                                 if(ik->data[a]) {
2783                                                         ik->data[a]->vec[1][0]= val;
2784                                                 }
2785                                         }
2786                                 }
2787                                 ik= ik->next;
2788                         }
2789                         editipo_changed(G.sipo, 0);
2790                 }
2791         }
2792         deselectall_editipo();
2793         BIF_undo_push("Join Ipo");
2794 }
2795
2796 void ipo_snap_menu(void)
2797 {
2798         short event;
2799         
2800         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2801         if(event < 1) return;
2802
2803         ipo_snap(event);
2804 }
2805
2806 void ipo_snap(short event)
2807 {
2808         EditIpo *ei;
2809         BezTriple *bezt;
2810         float dx = 0.0;
2811         int a, b;
2812         short ok, ok2;
2813         
2814         /* events:
2815          * Horizontal : 1
2816          * To Next: 2
2817          * To Frame: 3
2818          * To Current Frame: 4
2819          */
2820          
2821         get_status_editipo();
2822         
2823         /* map ipo-points for editing if scaled ipo */
2824         if (NLA_IPO_SCALED) {
2825                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
2826         }
2827
2828         ei= G.sipo->editipo;
2829         for(b=0; b<G.sipo->totipo; b++, ei++) {
2830                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2831                 
2832                         ok2= 0;
2833                         if(G.sipo->showkey) ok2= 1;
2834                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2835                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2836                         
2837                         if(ok2) {
2838                                 bezt= ei->icu->bezt;
2839                                 a= ei->icu->totvert;
2840                                 while(a--) {
2841                                         ok= 0;
2842                                         if(totipo_vert) {
2843                                                 if(bezt->f2 & SELECT) ok= 1;
2844                                         }
2845                                         else ok= 1;
2846                                         
2847                                         if(ok) {
2848                                                 if(event==1) {
2849                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2850                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2851                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2852                                                 }
2853                                                 else if(event==2) {
2854                                                         if(a) {
2855                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2856                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2857                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2858                                                         }
2859                                                 }
2860                                                 else if(event==3) {
2861                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2862                                                 }
2863                                                 else if(event==4) {     /* to current frame */
2864                                                         
2865                                                         if(ok2==1 || ok2==2) {
2866                                                                 
2867                                                                 if(G.sipo->blocktype==ID_SEQ) {
2868                                                                         Sequence *seq;
2869                                                         
2870                                                                         seq= (Sequence *)G.sipo->from;
2871                                                                         if(seq && (seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
2872                                                                                 dx= (float)(CFRA-seq->startdisp);
2873                                                                                 dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
2874                                                                                 
2875                                                                                 dx-= bezt->vec[1][0];
2876                                                                         } else {
2877                                                                                 dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2878                                                                         }
2879                                                                 }
2880                                                                 else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2881                                                                 
2882                                                                 bezt->vec[0][0]+= dx;
2883                                                                 bezt->vec[1][0]+= dx;
2884                                                                 bezt->vec[2][0]+= dx;
2885                                                         }
2886                                                 }
2887                                         }
2888                                         
2889                                         bezt++;
2890                                 }
2891                                 calchandles_ipocurve(ei->icu);
2892                         }
2893                 }
2894         }
2895         
2896         /* undo mapping of ipo-points for editing if scaled ipo */
2897         if (NLA_IPO_SCALED) {
2898                 actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
2899         }
2900         
2901         editipo_changed(G.sipo, 1);
2902         BIF_undo_push("Snap Ipo");
2903 }
2904
2905 void ipo_mirror_menu(void)
2906 {
2907         int mode = 0;
2908         mode= pupmenu("Mirror Over%t|Current Frame%x1|Vertical Axis%x2|Horizontal Axis%x3");
2909         
2910         if (mode == -1) return;
2911         
2912         ipo_mirror(mode);
2913 }
2914
2915 void ipo_mirror(short mode)
2916 {
2917         EditIpo *ei;
2918         BezTriple *bezt;
2919         
2920         int a, b;
2921         short ok, ok2, i;
2922         float diff;
2923         
2924         /* what's this for? */
2925         get_status_editipo();
2926