Animato: Added 'experimental' grouping schemes for F-Curves
[blender-staging.git] / source / blender / editors / animation / keyframing.c
1 /* Testing code for 2.5 animation system 
2  * Copyright 2009, Joshua Leung
3  */
4  
5 #include <stdio.h>
6 #include <stddef.h>
7 #include <string.h>
8 #include <math.h>
9 #include <float.h>
10
11 #include "MEM_guardedalloc.h"
12
13 #include "BLI_blenlib.h"
14 #include "BLI_arithb.h"
15 #include "BLI_dynstr.h"
16
17 #include "DNA_anim_types.h"
18 #include "DNA_action_types.h"
19 #include "DNA_armature_types.h"
20 #include "DNA_constraint_types.h"
21 #include "DNA_key_types.h"
22 #include "DNA_object_types.h"
23 #include "DNA_material_types.h"
24 #include "DNA_scene_types.h"
25 #include "DNA_userdef_types.h"
26 #include "DNA_windowmanager_types.h"
27
28 #include "BKE_animsys.h"
29 #include "BKE_action.h"
30 #include "BKE_fcurve.h"
31 #include "BKE_utildefines.h"
32 #include "BKE_context.h"
33 #include "BKE_key.h"
34 #include "BKE_material.h"
35
36 #include "ED_anim_api.h"
37 #include "ED_keyframing.h"
38 #include "ED_keyframes_edit.h"
39 #include "ED_screen.h"
40 #include "ED_util.h"
41
42 #include "WM_api.h"
43 #include "WM_types.h"
44
45 #include "RNA_access.h"
46 #include "RNA_define.h"
47 #include "RNA_types.h"
48
49 /* ************************************************** */
50 /* LOCAL TYPES AND DEFINES */
51
52 /* ----------- Common KeyData Sources ------------ */
53
54 /* temporary struct to gather data combos to keyframe */
55 typedef struct bCommonKeySrc {
56         struct bCommonKeySrc *next, *prev;
57                 
58                 /* general data/destination-source settings */
59         ID *id;                                 /* id-block this comes from */
60         char *rna_path;                 /* base path to use */  // xxx.... maybe we don't need this?
61         
62                 /* specific cases */
63         bPoseChannel *pchan;    /* only needed when doing recalcs... */
64 } bCommonKeySrc;
65
66 /* -------------- Keying Sets ------------------- */
67
68 #if 0 // XXX I'm not sure how these will work for now...
69
70 /* keying set - a set of channels that will be keyframed together  */
71 // TODO: move this to a header to allow custom sets someday?
72 typedef struct bKeyingSet {
73                 /* callback func to consider if keyingset should be included 
74                  * (by default, if this is undefined, item will be shown) 
75                  */
76         short (*include_cb)(struct bKeyingSet *, const char *);
77         
78         char name[48];                          /* name of keyingset */
79         int blocktype;                          /* nearest ID-blocktype to where data can be found */
80         short flag;                                     /* flags to use when setting keyframes */
81         
82         short chan_num;                         /* number of channels to insert keyframe in */
83         char (*paths)[256];                     /* adrcodes for channels to insert keys for (ideally would be variable-len, but limit of 32 will suffice) */
84 } bKeyingSet;
85
86 /* keying set context - an array of keying sets and the number of them */
87 typedef struct bKeyingContext {
88         bKeyingSet *keyingsets;         /* array containing the keyingsets of interest */
89         bKeyingSet *lastused;           /* item that was chosen last time*/
90         int tot;                                        /* number of keyingsets in */
91 } bKeyingContext;
92
93 #endif
94
95 /* ******************************************* */
96 /* Animation Data Validation */
97
98 /* Get (or add relevant data to be able to do so) F-Curve from the Active Action, 
99  * for the given Animation Data block. This assumes that all the destinations are valid.
100  */
101 FCurve *verify_fcurve (ID *id, const char group[], const char rna_path[], const int array_index, short add)
102 {
103         AnimData *adt;
104         bAction *act;
105         bActionGroup *grp;
106         FCurve *fcu;
107         
108         /* sanity checks */
109         if ELEM(NULL, id, rna_path)
110                 return NULL;
111         
112         /* init animdata if none available yet */
113         adt= BKE_animdata_from_id(id);
114         if ((adt == NULL) && (add))
115                 adt= BKE_id_add_animdata(id);
116         if (adt == NULL) { 
117                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
118                 return NULL;
119         }
120                 
121         /* init action if none available yet */
122         // TODO: need some wizardry to handle NLA stuff correct
123         if ((adt->action == NULL) && (add))
124                 adt->action= add_empty_action("Action");
125         act= adt->action;
126                 
127         /* try to find f-curve matching for this setting 
128          *      - add if not found and allowed to add one
129          *              TODO: add auto-grouping support? how this works will need to be resolved
130          */
131         if (act)
132                 fcu= list_find_fcurve(&act->curves, rna_path, array_index);
133         else
134                 fcu= NULL;
135         
136         if ((fcu == NULL) && (add)) {
137                 /* use default settings to make a F-Curve */
138                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
139                 
140                 fcu->flag |= (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES);
141                 if (act->curves.first==NULL) 
142                         fcu->flag |= FCURVE_ACTIVE;     /* first one added active */
143                         
144                 /* store path - make copy, and store that */
145                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
146                 fcu->array_index= array_index;
147                 
148                 
149                 /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
150                 if (group) {
151                         /* try to find group */
152                         grp= action_groups_find_named(act, group);
153                         
154                         /* no matching groups, so add one */
155                         if (grp == NULL) {
156                                 /* Add a new group, and make it active */
157                                 grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
158                                 
159                                 grp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
160                                 BLI_snprintf(grp->name, 64, group);
161                                 
162                                 BLI_addtail(&act->groups, grp);
163                                 BLI_uniquename(&act->groups, grp, "Group", offsetof(bActionGroup, name), 64);
164                                 
165                                 set_active_action_group(act, grp, 1);
166                         }
167                         
168                         /* add F-Curve to group */
169                         action_groups_add_channel(act, grp, fcu);
170                 }
171                 else {
172                         /* just add F-Curve to end of Action's list */
173                         BLI_addtail(&act->curves, fcu);
174                 }
175         }
176         
177         /* return the F-Curve */
178         return fcu;
179 }
180
181 /* ************************************************** */
182 /* KEYFRAME INSERTION */
183
184 /* -------------- BezTriple Insertion -------------------- */
185
186 /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
187 #define BEZT_INSERT_THRESH      0.00001
188
189 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
190  * Returns the index to insert at (data already at that index will be offset if replace is 0)
191  */
192 static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
193 {
194         int start=0, end=arraylen;
195         int loopbreaker= 0, maxloop= arraylen * 2;
196         
197         /* initialise replace-flag first */
198         *replace= 0;
199         
200         /* sneaky optimisations (don't go through searching process if...):
201          *      - keyframe to be added is to be added out of current bounds
202          *      - keyframe to be added would replace one of the existing ones on bounds
203          */
204         if ((arraylen <= 0) || (array == NULL)) {
205                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
206                 return 0;
207         }
208         else {
209                 /* check whether to add before/after/on */
210                 float framenum;
211                 
212                 /* 'First' Keyframe (when only one keyframe, this case is used) */
213                 framenum= array[0].vec[1][0];
214                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
215                         *replace = 1;
216                         return 0;
217                 }
218                 else if (frame < framenum)
219                         return 0;
220                         
221                 /* 'Last' Keyframe */
222                 framenum= array[(arraylen-1)].vec[1][0];
223                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
224                         *replace= 1;
225                         return (arraylen - 1);
226                 }
227                 else if (frame > framenum)
228                         return arraylen;
229         }
230         
231         
232         /* most of the time, this loop is just to find where to put it
233          * 'loopbreaker' is just here to prevent infinite loops 
234          */
235         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
236                 /* compute and get midpoint */
237                 int mid = (start + end) / 2;
238                 float midfra= array[mid].vec[1][0];
239                 
240                 /* check if exactly equal to midpoint */
241                 if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
242                         *replace = 1;
243                         return mid;
244                 }
245                 
246                 /* repeat in upper/lower half */
247                 if (frame > midfra)
248                         start= mid + 1;
249                 else if (frame < midfra)
250                         end= mid - 1;
251         }
252         
253         /* print error if loop-limit exceeded */
254         if (loopbreaker == (maxloop-1)) {
255                 printf("Error: binarysearch_bezt_index() was taking too long \n");
256                 
257                 // include debug info 
258                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
259         }
260         
261         /* not found, so return where to place it */
262         return start;
263 }
264
265 /* This function adds a given BezTriple to an F-Curve. It will allocate 
266  * memory for the array if needed, and will insert the BezTriple into a
267  * suitable place in chronological order.
268  * 
269  * NOTE: any recalculate of the F-Curve that needs to be done will need to 
270  *              be done by the caller.
271  */
272 int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt)
273 {
274         BezTriple *newb;
275         int i= 0;
276         
277         if (fcu->bezt) {
278                 short replace = -1;
279                 i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
280                 
281                 if (replace) {                  
282                         /* sanity check: 'i' may in rare cases exceed arraylen */
283                         // FIXME: do not overwrite handletype if just replacing...?
284                         if ((i >= 0) && (i < fcu->totvert))
285                                 *(fcu->bezt + i) = *bezt;
286                 }
287                 else {
288                         /* add new */
289                         newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple");
290                         
291                         /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
292                         if (i > 0)
293                                 memcpy(newb, fcu->bezt, i*sizeof(BezTriple));
294                         
295                         /* add beztriple to paste at index i */
296                         *(newb + i)= *bezt;
297                         
298                         /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
299                         if (i < fcu->totvert) 
300                                 memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple));
301                         
302                         /* replace (+ free) old with new */
303                         MEM_freeN(fcu->bezt);
304                         fcu->bezt= newb;
305                         
306                         fcu->totvert++;
307                 }
308         }
309         else {
310                 // TODO: need to check for old sample-data now...
311                 fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
312                 *(fcu->bezt)= *bezt;
313                 fcu->totvert= 1;
314         }
315         
316         
317         /* we need to return the index, so that some tools which do post-processing can 
318          * detect where we added the BezTriple in the array
319          */
320         return i;
321 }
322
323 /* This function is a wrapper for insert_bezt_icu, and should be used when
324  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
325  * else yet. 
326  * 
327  * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
328  */
329 void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast)
330 {
331         BezTriple beztr;
332         int a;
333         
334         /* set all three points, for nicer start position */
335         memset(&beztr, 0, sizeof(BezTriple));
336         beztr.vec[0][0]= x; 
337         beztr.vec[0][1]= y;
338         beztr.vec[1][0]= x;
339         beztr.vec[1][1]= y;
340         beztr.vec[2][0]= x;
341         beztr.vec[2][1]= y;
342         beztr.ipo= U.ipo_new; /* use default interpolation mode here... */
343         beztr.f1= beztr.f2= beztr.f3= SELECT;
344         beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one?
345         
346         /* add temp beztriple to keyframes */
347         a= insert_bezt_fcurve(fcu, &beztr);
348         
349         /* what if 'a' is a negative index? 
350          * for now, just exit to prevent any segfaults
351          */
352         if (a < 0) return;
353         
354         /* don't recalculate handles if fast is set
355          *      - this is a hack to make importers faster
356          *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
357          */
358         if (!fast) calchandles_fcurve(fcu);
359         
360         /* set handletype and interpolation */
361         if (fcu->totvert > 2) {
362                 BezTriple *bezt= (fcu->bezt + a);
363                 char h1, h2;
364                 
365                 /* set handles (autohandles by default) */
366                 h1= h2= HD_AUTO;
367                 
368                 if (a > 0) h1= (bezt-1)->h2;
369                 if (a < fcu->totvert-1) h2= (bezt+1)->h1;
370                 
371                 bezt->h1= h1;
372                 bezt->h2= h2;
373                 
374                 /* set interpolation from previous (if available) */
375                 if (a > 0) bezt->ipo= (bezt-1)->ipo;
376                 else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo;
377                         
378                 /* don't recalculate handles if fast is set
379                  *      - this is a hack to make importers faster
380                  *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
381                  */
382                 if (!fast) calchandles_fcurve(fcu);
383         }
384 }
385
386 /* -------------- 'Smarter' Keyframing Functions -------------------- */
387 /* return codes for new_key_needed */
388 enum {
389         KEYNEEDED_DONTADD = 0,
390         KEYNEEDED_JUSTADD,
391         KEYNEEDED_DELPREV,
392         KEYNEEDED_DELNEXT
393 } eKeyNeededStatus;
394
395 /* This helper function determines whether a new keyframe is needed */
396 /* Cases where keyframes should not be added:
397  *      1. Keyframe to be added bewteen two keyframes with similar values
398  *      2. Keyframe to be added on frame where two keyframes are already situated
399  *      3. Keyframe lies at point that intersects the linear line between two keyframes
400  */
401 static short new_key_needed (FCurve *fcu, float cFrame, float nValue) 
402 {
403         BezTriple *bezt=NULL, *prev=NULL;
404         int totCount, i;
405         float valA = 0.0f, valB = 0.0f;
406         
407         /* safety checking */
408         if (fcu == NULL) return KEYNEEDED_JUSTADD;
409         totCount= fcu->totvert;
410         if (totCount == 0) return KEYNEEDED_JUSTADD;
411         
412         /* loop through checking if any are the same */
413         bezt= fcu->bezt;
414         for (i=0; i<totCount; i++) {
415                 float prevPosi=0.0f, prevVal=0.0f;
416                 float beztPosi=0.0f, beztVal=0.0f;
417                         
418                 /* get current time+value */    
419                 beztPosi= bezt->vec[1][0];
420                 beztVal= bezt->vec[1][1];
421                         
422                 if (prev) {
423                         /* there is a keyframe before the one currently being examined */               
424                         
425                         /* get previous time+value */
426                         prevPosi= prev->vec[1][0];
427                         prevVal= prev->vec[1][1];
428                         
429                         /* keyframe to be added at point where there are already two similar points? */
430                         if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
431                                 return KEYNEEDED_DONTADD;
432                         }
433                         
434                         /* keyframe between prev+current points ? */
435                         if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
436                                 /* is the value of keyframe to be added the same as keyframes on either side ? */
437                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
438                                         return KEYNEEDED_DONTADD;
439                                 }
440                                 else {
441                                         float realVal;
442                                         
443                                         /* get real value of curve at that point */
444                                         realVal= evaluate_fcurve(fcu, cFrame);
445                                         
446                                         /* compare whether it's the same as proposed */
447                                         if (IS_EQ(realVal, nValue)) 
448                                                 return KEYNEEDED_DONTADD;
449                                         else 
450                                                 return KEYNEEDED_JUSTADD;
451                                 }
452                         }
453                         
454                         /* new keyframe before prev beztriple? */
455                         if (cFrame < prevPosi) {
456                                 /* A new keyframe will be added. However, whether the previous beztriple
457                                  * stays around or not depends on whether the values of previous/current
458                                  * beztriples and new keyframe are the same.
459                                  */
460                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
461                                         return KEYNEEDED_DELNEXT;
462                                 else 
463                                         return KEYNEEDED_JUSTADD;
464                         }
465                 }
466                 else {
467                         /* just add a keyframe if there's only one keyframe 
468                          * and the new one occurs before the exisiting one does.
469                          */
470                         if ((cFrame < beztPosi) && (totCount==1))
471                                 return KEYNEEDED_JUSTADD;
472                 }
473                 
474                 /* continue. frame to do not yet passed (or other conditions not met) */
475                 if (i < (totCount-1)) {
476                         prev= bezt;
477                         bezt++;
478                 }
479                 else
480                         break;
481         }
482         
483         /* Frame in which to add a new-keyframe occurs after all other keys
484          * -> If there are at least two existing keyframes, then if the values of the
485          *       last two keyframes and the new-keyframe match, the last existing keyframe
486          *       gets deleted as it is no longer required.
487          * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
488          *       keyframe is not equal to last keyframe.
489          */
490         bezt= (fcu->bezt + (fcu->totvert - 1));
491         valA= bezt->vec[1][1];
492         
493         if (prev)
494                 valB= prev->vec[1][1];
495         else 
496                 valB= bezt->vec[1][1] + 1.0f; 
497                 
498         if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) 
499                 return KEYNEEDED_DELPREV;
500         else 
501                 return KEYNEEDED_JUSTADD;
502 }
503
504 /* ------------------ RNA Data-Access Functions ------------------ */
505
506 /* Try to read value using RNA-properties obtained already */
507 static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index)
508 {
509         float value= 0.0f;
510         
511         switch (RNA_property_type(ptr, prop)) {
512                 case PROP_BOOLEAN:
513                         if (RNA_property_array_length(ptr, prop))
514                                 value= (float)RNA_property_boolean_get_index(ptr, prop, index);
515                         else
516                                 value= (float)RNA_property_boolean_get(ptr, prop);
517                         break;
518                 case PROP_INT:
519                         if (RNA_property_array_length(ptr, prop))
520                                 value= (float)RNA_property_int_get_index(ptr, prop, index);
521                         else
522                                 value= (float)RNA_property_int_get(ptr, prop);
523                         break;
524                 case PROP_FLOAT:
525                         if (RNA_property_array_length(ptr, prop))
526                                 value= RNA_property_float_get_index(ptr, prop, index);
527                         else
528                                 value= RNA_property_float_get(ptr, prop);
529                         break;
530                 case PROP_ENUM:
531                         value= (float)RNA_property_enum_get(ptr, prop);
532                         break;
533                 default:
534                         break;
535         }
536         
537         return value;
538 }
539
540 /* ------------------ 'Visual' Keyframing Functions ------------------ */
541
542 /* internal status codes for visualkey_can_use */
543 enum {
544         VISUALKEY_NONE = 0,
545         VISUALKEY_LOC,
546         VISUALKEY_ROT,
547 };
548
549 /* This helper function determines if visual-keyframing should be used when  
550  * inserting keyframes for the given channel. As visual-keyframing only works
551  * on Object and Pose-Channel blocks, this should only get called for those 
552  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying 
553  * settings is on.
554  */
555 static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop)
556 {
557         //Object *ob= NULL;
558         bConstraint *con= NULL;
559         short searchtype= VISUALKEY_NONE;
560         
561 #if 0 //  XXX old animation system      
562         /* validate data */
563         if ((id == NULL) || (GS(id->name)!=ID_OB) || !(ELEM(blocktype, ID_OB, ID_PO))) 
564                 return 0;       
565         
566         /* get first constraint and determine type of keyframe constraints to check for*/
567         ob= (Object *)id;
568         
569         if (blocktype == ID_OB) {
570                 con= ob->constraints.first;
571                 
572                 if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z))
573                         searchtype= VISUALKEY_LOC;
574                 else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z))
575                         searchtype= VISUALKEY_ROT;
576         }
577         else if (blocktype == ID_PO) {
578                 bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
579                 con= pchan->constraints.first;
580                 
581                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z))
582                         searchtype= VISUALKEY_LOC;
583                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z))
584                         searchtype= VISUALKEY_ROT;
585         }
586 #endif
587         
588         /* only search if a searchtype and initial constraint are available */
589         if (searchtype && con) {
590                 for (; con; con= con->next) {
591                         /* only consider constraint if it is not disabled, and has influence */
592                         if (con->flag & CONSTRAINT_DISABLE) continue;
593                         if (con->enforce == 0.0f) continue;
594                         
595                         /* some constraints may alter these transforms */
596                         switch (con->type) {
597                                 /* multi-transform constraints */
598                                 case CONSTRAINT_TYPE_CHILDOF:
599                                         return 1;
600                                 case CONSTRAINT_TYPE_TRANSFORM:
601                                         return 1;
602                                 case CONSTRAINT_TYPE_FOLLOWPATH:
603                                         return 1;
604                                 case CONSTRAINT_TYPE_KINEMATIC:
605                                         return 1;
606                                         
607                                 /* single-transform constraits  */
608                                 case CONSTRAINT_TYPE_TRACKTO:
609                                         if (searchtype==VISUALKEY_ROT) return 1;
610                                         break;
611                                 case CONSTRAINT_TYPE_ROTLIMIT:
612                                         if (searchtype==VISUALKEY_ROT) return 1;
613                                         break;
614                                 case CONSTRAINT_TYPE_LOCLIMIT:
615                                         if (searchtype==VISUALKEY_LOC) return 1;
616                                         break;
617                                 case CONSTRAINT_TYPE_ROTLIKE:
618                                         if (searchtype==VISUALKEY_ROT) return 1;
619                                         break;
620                                 case CONSTRAINT_TYPE_DISTLIMIT:
621                                         if (searchtype==VISUALKEY_LOC) return 1;
622                                         break;
623                                 case CONSTRAINT_TYPE_LOCLIKE:
624                                         if (searchtype==VISUALKEY_LOC) return 1;
625                                         break;
626                                 case CONSTRAINT_TYPE_LOCKTRACK:
627                                         if (searchtype==VISUALKEY_ROT) return 1;
628                                         break;
629                                 case CONSTRAINT_TYPE_MINMAX:
630                                         if (searchtype==VISUALKEY_LOC) return 1;
631                                         break;
632                                 
633                                 default:
634                                         break;
635                         }
636                 }
637         }
638         
639         /* when some condition is met, this function returns, so here it can be 0 */
640         return 0;
641 }
642
643 /* This helper function extracts the value to use for visual-keyframing 
644  * In the event that it is not possible to perform visual keying, try to fall-back
645  * to using the default method. Assumes that all data it has been passed is valid.
646  */
647 // xxx... ptr here should be struct that data is in.... prop is the channel that's being used
648 static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index)
649 {
650 #if 0 // XXX old animation system
651         Object *ob;
652         void *poin = NULL;
653         int index, vartype;
654         
655         /* validate situtation */
656         if ((id==NULL) || (GS(id->name)!=ID_OB) || (ELEM(blocktype, ID_OB, ID_PO)==0))
657                 return 0.0f;
658                 
659         /* get object */
660         ob= (Object *)id;
661         
662         /* only valid for objects or posechannels */
663         if (blocktype == ID_OB) {
664                 /* parented objects are not supported, as the effects of the parent
665                  * are included in the matrix, which kindof beats the point
666                  */
667                 if (ob->parent == NULL) {
668                         /* only Location or Rotation keyframes are supported now */
669                         if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z)) {
670                                 /* assumes that OB_LOC_Z > OB_LOC_Y > OB_LOC_X */
671                                 index= adrcode - OB_LOC_X;
672                                 
673                                 return ob->obmat[3][index];
674                         }
675                         else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
676                                 float eul[3];
677                                 
678                                 /* assumes that OB_ROT_Z > OB_ROT_Y > OB_ROT_X */
679                                 index= adrcode - OB_ROT_X;
680                                 
681                                 Mat4ToEul(ob->obmat, eul);
682                                 return eul[index]*(5.72958f);
683                         }
684                 }
685         }
686         else if (blocktype == ID_PO) {
687                 bPoseChannel *pchan;
688                 float tmat[4][4];
689                 
690                 /* get data to use */
691                 pchan= get_pose_channel(ob->pose, actname);
692                 
693                 /* Although it is not strictly required for this particular space conversion, 
694                  * arg1 must not be null, as there is a null check for the other conversions to
695                  * be safe. Therefore, the active object is passed here, and in many cases, this
696                  * will be what owns the pose-channel that is getting this anyway.
697                  */
698                 Mat4CpyMat4(tmat, pchan->pose_mat);
699                 constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
700                 
701                 /* Loc, Rot/Quat keyframes are supported... */
702                 if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z)) {
703                         /* assumes that AC_LOC_Z > AC_LOC_Y > AC_LOC_X */
704                         index= adrcode - AC_LOC_X;
705                         
706                         /* only use for non-connected bones */
707                         if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
708                                 return tmat[3][index];
709                         else if (pchan->bone->parent == NULL)
710                                 return tmat[3][index];
711                 }
712                 else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z)) {
713                         float trimat[3][3], quat[4];
714                         
715                         /* assumes that AC_QUAT_Z > AC_QUAT_Y > AC_QUAT_X > AC_QUAT_W */
716                         index= adrcode - AC_QUAT_W;
717                         
718                         Mat3CpyMat4(trimat, tmat);
719                         Mat3ToQuat_is_ok(trimat, quat);
720                         
721                         return quat[index];
722                 }
723         }
724 #endif  // XXX old animation system
725         
726         /* as the function hasn't returned yet, read value from system in the default way */
727         return setting_get_rna_value(ptr, prop, array_index);
728 }
729
730 /* ------------------------- Insert Key API ------------------------- */
731
732 /* Main Keyframing API call:
733  *      Use this when validation of necessary animation data isn't necessary as it
734  *      already exists. It will insert a keyframe using the current value being keyframed.
735  *      
736  *      The flag argument is used for special settings that alter the behaviour of
737  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
738  *      and extra keyframe filtering.
739  */
740 short insertkey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
741 {       
742         PointerRNA id_ptr, ptr;
743         PropertyRNA *prop;
744         FCurve *fcu;
745         
746         /* validate pointer first - exit if failure*/
747         RNA_id_pointer_create(id, &id_ptr);
748         if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) {
749                 printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID \n");
750                 return 0;
751         }
752         
753         /* get F-Curve */
754         fcu= verify_fcurve(id, group, rna_path, array_index, 1);
755         
756         /* only continue if we have an F-Curve to add keyframe to */
757         if (fcu) {
758                 float curval= 0.0f;
759                 
760                 /* apply special time tweaking */
761                         // XXX check on this stuff...
762                 if (GS(id->name) == ID_OB) {
763                         //Object *ob= (Object *)id;
764                         
765                         /* apply NLA-scaling (if applicable) */
766                         //cfra= get_action_frame(ob, cfra);
767                         
768                         /* ancient time-offset cruft */
769                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
770                         //      /* actually frametofloat calc again! */
771                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
772                         //}
773                 }
774                 
775                 /* obtain value to give keyframe */
776                 if ( (flag & INSERTKEY_MATRIX) && 
777                          (visualkey_can_use(&ptr, prop)) ) 
778                 {
779                         /* visual-keying is only available for object and pchan datablocks, as 
780                          * it works by keyframing using a value extracted from the final matrix 
781                          * instead of using the kt system to extract a value.
782                          */
783                         curval= visualkey_get_value(&ptr, prop, array_index);
784                 }
785                 else {
786                         /* read value from system */
787                         curval= setting_get_rna_value(&ptr, prop, array_index);
788                 }
789                 
790                 /* only insert keyframes where they are needed */
791                 if (flag & INSERTKEY_NEEDED) {
792                         short insert_mode;
793                         
794                         /* check whether this curve really needs a new keyframe */
795                         insert_mode= new_key_needed(fcu, cfra, curval);
796                         
797                         /* insert new keyframe at current frame */
798                         if (insert_mode)
799                                 insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
800                         
801                         /* delete keyframe immediately before/after newly added */
802                         switch (insert_mode) {
803                                 case KEYNEEDED_DELPREV:
804                                         delete_fcurve_key(fcu, fcu->totvert-2, 1);
805                                         break;
806                                 case KEYNEEDED_DELNEXT:
807                                         delete_fcurve_key(fcu, 1, 1);
808                                         break;
809                         }
810                         
811                         /* only return success if keyframe added */
812                         if (insert_mode)
813                                 return 1;
814                 }
815                 else {
816                         /* just insert keyframe */
817                         insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
818                         
819                         /* return success */
820                         return 1;
821                 }
822         }
823         
824         /* return failure */
825         return 0;
826 }
827
828 /* ************************************************** */
829 /* KEYFRAME DELETION */
830
831 /* Main Keyframing API call:
832  *      Use this when validation of necessary animation data isn't necessary as it
833  *      already exists. It will delete a keyframe at the current frame.
834  *      
835  *      The flag argument is used for special settings that alter the behaviour of
836  *      the keyframe deletion. These include the quick refresh options.
837  */
838 short deletekey (ID *id, const char group[], const char rna_path[], int array_index, float cfra, short flag)
839 {
840         AnimData *adt;
841         FCurve *fcu;
842         
843         /* get F-Curve
844          * Note: here is one of the places where we don't want new Action + F-Curve added!
845          *              so 'add' var must be 0
846          */
847         // XXX we don't check the validity of the path here yet, but it should be ok...
848         fcu= verify_fcurve(id, group, rna_path, array_index, 0);
849         adt= BKE_animdata_from_id(id);
850         
851         /* only continue if we have an ipo-curve to remove keyframes from */
852         if (adt && adt->action && fcu) {
853                 bAction *act= adt->action;
854                 short found = -1;
855                 int i;
856                 
857                 /* apply special time tweaking */
858                 if (GS(id->name) == ID_OB) {
859                         //Object *ob= (Object *)id;
860                         
861                         /* apply NLA-scaling (if applicable) */
862                         //      cfra= get_action_frame(ob, cfra);
863                         
864                         /* ancient time-offset cruft */
865                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
866                         //      /* actually frametofloat calc again! */
867                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
868                         //}
869                 }
870                 
871                 /* try to find index of beztriple to get rid of */
872                 i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
873                 if (found) {                    
874                         /* delete the key at the index (will sanity check + do recalc afterwards) */
875                         delete_fcurve_key(fcu, i, 1);
876                         
877                         /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */
878                         // XXX how do we handle drivers then?
879                         if (fcu->totvert == 0) {
880                                 BLI_remlink(&act->curves, fcu);
881                                 free_fcurve(fcu);
882                         }
883                         
884                         /* return success */
885                         return 1;
886                 }
887         }
888         
889         /* return failure */
890         return 0;
891 }
892
893 /* ******************************************* */
894 /* KEYFRAME MODIFICATION */
895
896 /* mode for common_modifykey */
897 enum {
898         COMMONKEY_MODE_INSERT = 0,
899         COMMONKEY_MODE_DELETE,
900 } eCommonModifyKey_Modes;
901
902 #if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course
903
904 /* --------- KeyingSet Adrcode Getters ------------ */
905
906 /* initialise a channel-getter storage */
907 static void ks_adrcodegetter_init (bKS_AdrcodeGetter *kag, bKeyingSet *ks, bCommonKeySrc *cks)
908 {
909         /* error checking */
910         if (kag == NULL)
911                 return;
912         
913         if (ELEM(NULL, ks, cks)) {
914                 /* set invalid settings that won't cause harm */
915                 kag->ks= NULL;
916                 kag->cks= NULL;
917                 kag->index= -2;
918                 kag->tot= 0;
919         }
920         else {
921                 /* store settings */
922                 kag->ks= ks;
923                 kag->cks= cks;
924                 
925                 /* - index is -1, as that allows iterators to return first element
926                  * - tot is chan_num by default, but may get overriden if -1 is encountered (for extension-type getters)
927                  */
928                 kag->index= -1;
929                 kag->tot= ks->chan_num;
930         }
931 }
932
933 /* 'default' channel-getter that will be used when iterating through keyingset's channels 
934  *       - iteration will stop when adrcode <= 0 is encountered, so we use that as escape
935  */
936 static short ks_getnextadrcode_default (bKS_AdrcodeGetter *kag)
937 {       
938         bKeyingSet *ks= (kag)? kag->ks : NULL;
939         
940         /* error checking */
941         if (ELEM(NULL, kag, ks)) return 0;
942         if (kag->tot <= 0) return 0;
943         
944         kag->index++;
945         if ((kag->index < 0) || (kag->index >= kag->tot)) return 0;
946         
947         /* return the adrcode stored at index then */
948         return ks->adrcodes[kag->index];
949 }
950
951 /* add map flag (for MTex channels, as certain ones need special offset) */
952 static short ks_getnextadrcode_addmap (bKS_AdrcodeGetter *kag)
953 {
954         short adrcode= ks_getnextadrcode_default(kag);
955         
956         /* if there was an adrcode returned, assume that kag stuff is set ok */
957         if (adrcode) {
958                 bCommonKeySrc *cks= kag->cks;
959                 bKeyingSet *ks= kag->ks;
960                 
961                 if (ELEM3(ks->blocktype, ID_MA, ID_LA, ID_WO)) {
962                         switch (adrcode) {
963                                 case MAP_OFS_X: case MAP_OFS_Y: case MAP_OFS_Z:
964                                 case MAP_SIZE_X: case MAP_SIZE_Y: case MAP_SIZE_Z:
965                                 case MAP_R: case MAP_G: case MAP_B: case MAP_DVAR:
966                                 case MAP_COLF: case MAP_NORF: case MAP_VARF: case MAP_DISP:
967                                         adrcode += cks->map;
968                                         break;
969                         }
970                 }
971         }
972         
973         /* adrcode must be returned! */
974         return adrcode;
975 }
976
977 /* extend posechannel keyingsets with rotation info (when KAG_CHAN_EXTEND is encountered) 
978  *      - iteration will stop when adrcode <= 0 is encountered, so we use that as escape
979  *      - when we encounter KAG_CHAN_EXTEND as adrcode, start returning our own
980  */
981 static short ks_getnextadrcode_pchanrot (bKS_AdrcodeGetter *kag)
982 {       
983         /* hardcoded adrcode channels used here only 
984          *      - length is keyed-channels + 1 (last item must be 0 to escape)
985          */
986         static short quat_adrcodes[5] = {AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z, 0};
987         static short eul_adrcodes[4] = {AC_EUL_X, AC_EUL_Y, AC_EUL_Z, 0};
988                 
989         /* useful variables */
990         bKeyingSet *ks= (kag)? kag->ks : NULL;
991         bCommonKeySrc *cks= (kag) ? kag->cks : NULL;
992         short index, adrcode;
993         
994         /* error checking */
995         if (ELEM3(NULL, kag, ks, cks)) return 0;
996         if (ks->chan_num <= 0) return 0;
997         
998         /* get index 
999          *      - if past the last item (kag->tot), return stuff from our static arrays
1000          *      - otherwise, just keep returning stuff from the keyingset (but check out for -1!) 
1001          */
1002         kag->index++;
1003         if (kag->index < 0)
1004                 return 0;
1005         
1006         /* normal (static stuff) */
1007         if (kag->index < kag->tot) {
1008                 /* get adrcode, and return if not KAG_CHAN_EXTEND (i.e. point for start of iteration) */
1009                 adrcode= ks->adrcodes[kag->index];
1010                 
1011                 if (adrcode != KAG_CHAN_EXTEND) 
1012                         return adrcode;
1013                 else    
1014                         kag->tot= kag->index;
1015         }
1016                 
1017         /* based on current rotation-mode
1018          *      - index can be at most 5, if we are to prevent segfaults
1019          */
1020         index= kag->index - kag->tot;
1021         if ((index < 0) || (index > 5))
1022                 return 0;
1023         
1024         if (cks->pchan && cks->pchan->rotmode)
1025                 return eul_adrcodes[index];
1026         else
1027                 return quat_adrcodes[index];
1028 }
1029
1030 /* ------------- KeyingSet Defines ------------ */
1031 /* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */
1032
1033 /* macro for defining keyingset contexts */
1034 #define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)}
1035
1036 /* --- */
1037
1038 /* check if option not available for deleting keys */
1039 static short incl_non_del_keys (bKeyingSet *ks, const char mode[])
1040 {
1041         /* as optimisation, assume that it is sufficient to check only first letter
1042          * of mode (int comparison should be faster than string!)
1043          */
1044         //if (strcmp(mode, "Delete")==0)
1045         if (mode && mode[0]=='D')
1046                 return 0;
1047         
1048         return 1;
1049 }
1050
1051 /* Object KeyingSets  ------ */
1052
1053 /* check if include shapekey entry  */
1054 static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[])
1055 {
1056         //Object *ob= (G.obedit)? (G.obedit) : (OBACT); // XXX
1057         Object *ob= NULL;
1058         char *newname= NULL;
1059         
1060         if(ob==NULL)
1061                 return 0;
1062         
1063         /* not available for delete mode */
1064         if (strcmp(mode, "Delete")==0)
1065                 return 0;
1066         
1067         /* check if is geom object that can get shapekeys */
1068         switch (ob->type) {
1069                 /* geometry? */
1070                 case OB_MESH:           newname= "Mesh";                break;
1071                 case OB_CURVE:          newname= "Curve";               break;
1072                 case OB_SURF:           newname= "Surface";             break;
1073                 case OB_LATTICE:        newname= "Lattice";             break;
1074                 
1075                 /* not geometry! */
1076                 default:
1077                         return 0;
1078         }
1079         
1080         /* if ks is shapekey entry (this could be callled for separator before too!) */
1081         if (ks->flag == -3)
1082                 BLI_strncpy(ks->name, newname, sizeof(ks->name));
1083         
1084         /* if it gets here, it's ok */
1085         return 1;
1086 }
1087
1088 /* array for object keyingset defines */
1089 bKeyingSet defks_v3d_object[] = 
1090 {
1091         /* include_cb, adrcode-getter, name, blocktype, flag, chan_num, adrcodes */
1092         {NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
1093         {NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1094         {NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1095         
1096         {NULL, "%l", 0, -1, 0, {0}}, // separator
1097         
1098         {NULL, "LocRot", ID_OB, 0, 6, 
1099                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1100                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1101                  
1102         {NULL, "LocScale", ID_OB, 0, 6, 
1103                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1104                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1105                  
1106         {NULL, "LocRotScale", ID_OB, 0, 9, 
1107                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1108                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
1109                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1110                  
1111         {NULL, "RotScale", ID_OB, 0, 6, 
1112                 {OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
1113                  OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
1114         
1115         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
1116         
1117         {incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
1118         {incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1119         
1120         {incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6, 
1121                 {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
1122                  OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
1123         
1124         {NULL, "%l", 0, -1, 0, {0}}, // separator
1125         
1126         {NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option...
1127         {NULL, "Available", ID_OB, -2, 0, {0}},
1128         
1129         {incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry)
1130         {incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}}
1131 };
1132
1133 /* PoseChannel KeyingSets  ------ */
1134
1135 /* array for posechannel keyingset defines */
1136 bKeyingSet defks_v3d_pchan[] = 
1137 {
1138         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1139         {NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
1140         {NULL, "Rot", ID_PO, COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
1141         {NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
1142         
1143         {NULL, "%l", 0, -1, 0, {0}}, // separator
1144         
1145         {NULL, "LocRot", ID_PO, COMMONKEY_PCHANROT, 4, 
1146                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
1147                  KAG_CHAN_EXTEND}},
1148                  
1149         {NULL, "LocScale", ID_PO, 0, 6, 
1150                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
1151                  AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
1152                  
1153         {NULL, "LocRotScale", ID_PO, COMMONKEY_PCHANROT, 7, 
1154                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
1155                  KAG_CHAN_EXTEND}},
1156                  
1157         {NULL, "RotScale", ID_PO, 0, 4, 
1158                 {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
1159                  KAG_CHAN_EXTEND}},
1160         
1161         {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
1162         
1163         {incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
1164         {incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
1165         
1166         {incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 4, 
1167                 {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, KAG_CHAN_EXTEND}},
1168         
1169         {NULL, "%l", 0, -1, 0, {0}}, // separator
1170         
1171         {NULL, "Available", ID_PO, -2, 0, {0}}
1172 };
1173
1174 /* Material KeyingSets  ------ */
1175
1176 /* array for material keyingset defines */
1177 bKeyingSet defks_buts_shading_mat[] = 
1178 {
1179         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1180         {NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}},
1181         {NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}},
1182         {NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}},
1183         {NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags
1184         
1185         {NULL, "%l", 0, -1, 0, {0}}, // separator
1186         
1187         {NULL, "All Color", ID_MA, 0, 18, 
1188                 {MA_COL_R,MA_COL_G,MA_COL_B,
1189                  MA_ALPHA,MA_HASIZE, MA_MODE,
1190                  MA_SPEC_R,MA_SPEC_G,MA_SPEC_B,
1191                  MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD,
1192                  MA_MODE,MA_TRANSLU,MA_ADD}},
1193                  
1194         {NULL, "All Mirror", ID_MA, 0, 5, 
1195                 {MA_RAYM,MA_FRESMIR,MA_FRESMIRI,
1196                  MA_FRESTRA,MA_FRESTRAI}},
1197         
1198         {NULL, "%l", 0, -1, 0, {0}}, // separator
1199         
1200         {NULL, "Ofs", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1201         {NULL, "Size", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1202         
1203         {NULL, "All Mapping", ID_MA, COMMONKEY_ADDMAP, 14, 
1204                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1205                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1206                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1207                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1208         
1209         {NULL, "%l", 0, -1, 0, {0}}, // separator
1210         
1211         {NULL, "Available", ID_MA, -2, 0, {0}}
1212 };
1213
1214 /* World KeyingSets  ------ */
1215
1216 /* array for world keyingset defines */
1217 bKeyingSet defks_buts_shading_wo[] = 
1218 {
1219         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1220         {NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}},
1221         {NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}},
1222         
1223         {NULL, "%l", 0, -1, 0, {0}}, // separator
1224         
1225         {NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}},
1226         {NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}},
1227         
1228         
1229         {NULL, "%l", 0, -1, 0, {0}}, // separator
1230         
1231         {NULL, "Ofs", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1232         {NULL, "Size", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1233         
1234         {NULL, "All Mapping", ID_WO, COMMONKEY_ADDMAP, 14, 
1235                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1236                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1237                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1238                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1239         
1240         {NULL, "%l", 0, -1, 0, {0}}, // separator
1241         
1242         {NULL, "Available", ID_WO, -2, 0, {0}}
1243 };
1244
1245 /* Lamp KeyingSets  ------ */
1246
1247 /* array for lamp keyingset defines */
1248 bKeyingSet defks_buts_shading_la[] = 
1249 {
1250         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1251         {NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}},
1252         {NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}},
1253         {NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}},
1254         
1255         {NULL, "%l", 0, -1, 0, {0}}, // separator
1256         
1257         {NULL, "Ofs", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
1258         {NULL, "Size", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
1259         
1260         {NULL, "All Mapping", ID_LA, COMMONKEY_ADDMAP, 14, 
1261                 {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
1262                  MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
1263                  MAP_R,MAP_G,MAP_B,MAP_DVAR,
1264                  MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
1265         
1266         {NULL, "%l", 0, -1, 0, {0}}, // separator
1267         
1268         {NULL, "Available", ID_LA, -2, 0, {0}}
1269 };
1270
1271 /* Texture KeyingSets  ------ */
1272
1273 /* array for texture keyingset defines */
1274 bKeyingSet defks_buts_shading_tex[] = 
1275 {
1276         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1277         {NULL, "Clouds", ID_TE, 0, 5, 
1278                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
1279                  TE_MG_TYP,TE_N_BAS1}},
1280         
1281         {NULL, "Marble", ID_TE, 0, 7, 
1282                 {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
1283                  TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
1284                  
1285         {NULL, "Stucci", ID_TE, 0, 5, 
1286                 {TE_NSIZE,TE_NTYPE,TE_TURB,
1287                  TE_MG_TYP,TE_N_BAS1}},
1288                  
1289         {NULL, "Wood", ID_TE, 0, 6, 
1290                 {TE_NSIZE,TE_NTYPE,TE_TURB,
1291                  TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
1292                  
1293         {NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}},
1294         
1295         {NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}},      
1296                 
1297         {NULL, "Musgrave", ID_TE, 0, 6, 
1298                 {TE_MG_TYP,TE_MGH,TE_MG_LAC,
1299                  TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}},
1300                  
1301         {NULL, "Voronoi", ID_TE, 0, 9, 
1302                 {TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4,
1303                 TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT,
1304                 TE_ISCA,TE_NSIZE}},
1305                 
1306         {NULL, "Distorted Noise", ID_TE, 0, 4, 
1307                 {TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}},
1308         
1309         {NULL, "Color Filter", ID_TE, 0, 5, 
1310                 {TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}},
1311         
1312         {NULL, "%l", 0, -1, 0, {0}}, // separator
1313         
1314         {NULL, "Available", ID_TE, -2, 0, {0}}
1315 };
1316
1317 /* Object Buttons KeyingSets  ------ */
1318
1319 /* check if include particles entry  */
1320 static short incl_buts_ob (bKeyingSet *ks, const char mode[])
1321 {
1322         //Object *ob= OBACT; // xxx
1323         Object *ob= NULL;
1324         /* only if object is mesh type */
1325         
1326         if(ob==NULL) return 0;
1327         return (ob->type == OB_MESH);
1328 }
1329
1330 /* array for texture keyingset defines */
1331 bKeyingSet defks_buts_object[] = 
1332 {
1333         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1334         {incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}},
1335         {incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}},
1336         {incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}},
1337         
1338         {NULL, "%l", 0, -1, 0, {0}}, // separator
1339         
1340         {NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}},
1341         {NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}},
1342         
1343         {NULL, "%l", 0, -1, 0, {0}}, // separator
1344         
1345         {NULL, "Available", ID_OB, -2, 0, {0}}  // this will include ob-transforms too!
1346 };
1347
1348 /* Camera Buttons KeyingSets  ------ */
1349
1350 /* check if include internal-renderer entry  */
1351 static short incl_buts_cam1 (bKeyingSet *ks, const char mode[])
1352 {
1353         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
1354         /* only if renderer is internal renderer */
1355         return (scene->r.renderer==R_INTERN);
1356 }
1357
1358 /* check if include external-renderer entry  */
1359 static short incl_buts_cam2 (bKeyingSet *ks, const char mode[])
1360 {
1361         Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
1362         /* only if renderer is internal renderer */
1363         return (scene->r.renderer!=R_INTERN);
1364 }
1365
1366 /* array for camera keyingset defines */
1367 bKeyingSet defks_buts_cam[] = 
1368 {
1369         /* include_cb, name, blocktype, flag, chan_num, adrcodes */
1370         {NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}},
1371         {NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}},
1372         {NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}},
1373         
1374         {NULL, "%l", 0, -1, 0, {0}}, // separator
1375         
1376         
1377         {incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}},
1378         {incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}},
1379         
1380         {NULL, "%l", 0, -1, 0, {0}}, // separator
1381         
1382         {NULL, "Available", ID_CA, -2, 0, {0}}
1383 };
1384
1385 /* --- */
1386
1387 /* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */
1388 bKeyingContext ks_contexts[] = 
1389 {
1390         KSC_TEMPLATE(v3d_object),
1391         KSC_TEMPLATE(v3d_pchan),
1392         
1393         KSC_TEMPLATE(buts_shading_mat),
1394         KSC_TEMPLATE(buts_shading_wo),
1395         KSC_TEMPLATE(buts_shading_la),
1396         KSC_TEMPLATE(buts_shading_tex),
1397
1398         KSC_TEMPLATE(buts_object),
1399         KSC_TEMPLATE(buts_cam)
1400 };
1401
1402 /* Keying Context Enumeration - Must keep in sync with definitions*/
1403 typedef enum eKS_Contexts {
1404         KSC_V3D_OBJECT = 0,
1405         KSC_V3D_PCHAN,
1406         
1407         KSC_BUTS_MAT,
1408         KSC_BUTS_WO,
1409         KSC_BUTS_LA,
1410         KSC_BUTS_TEX,
1411         
1412         KSC_BUTS_OB,
1413         KSC_BUTS_CAM,
1414         
1415                 /* make sure this last one remains untouched! */
1416         KSC_TOT_TYPES
1417 } eKS_Contexts;
1418
1419
1420 /* ---------------- KeyingSet Tools ------------------- */
1421
1422 /* helper for commonkey_context_get() -  get keyingsets for 3d-view */
1423 static void commonkey_context_getv3d (const bContext *C, ListBase *sources, bKeyingContext **ksc)
1424 {
1425         Scene *scene= CTX_data_scene(C);
1426         Object *ob;
1427         IpoCurve *icu;
1428         
1429         if ((OBACT) && (OBACT->flag & OB_POSEMODE)) {
1430                 bPoseChannel *pchan;
1431                 
1432                 /* pose-level */
1433                 ob= OBACT;
1434                 *ksc= &ks_contexts[KSC_V3D_PCHAN];
1435                         // XXX
1436                 //set_pose_keys(ob);  /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
1437                 
1438                 /* loop through posechannels */
1439                 for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
1440                         if (pchan->flag & POSE_KEY) {
1441                                 bCommonKeySrc *cks;
1442                                 
1443                                 /* add new keyframing destination */
1444                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1445                                 BLI_addtail(sources, cks);
1446                                 
1447                                 /* set id-block to key to, and action */
1448                                 cks->id= (ID *)ob;
1449                                 cks->act= ob->action;
1450                                 
1451                                 /* set pchan */
1452                                 cks->pchan= pchan;
1453                                 cks->actname= pchan->name;
1454                         }
1455                 }
1456         }
1457         else {
1458                 /* object-level */
1459                 *ksc= &ks_contexts[KSC_V3D_OBJECT];
1460                 
1461                 /* loop through bases */
1462                 // XXX but we're only supposed to do this on editable ones, not just selected ones!
1463                 CTX_DATA_BEGIN(C, Base*, base, selected_bases) {
1464                         bCommonKeySrc *cks;
1465                         
1466                         /* add new keyframing destination */
1467                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1468                         BLI_addtail(sources, cks);
1469                         
1470                         /* set id-block to key to */
1471                         ob= base->object;
1472                         cks->id= (ID *)ob;
1473                         
1474                         /* when ob's keyframes are in an action, default to using 'Object' as achan name */
1475                         if (ob->ipoflag & OB_ACTION_OB)
1476                                 cks->actname= "Object";
1477                         
1478                         /* set ipo-flags */
1479                         // TODO: add checks for lib-linked data
1480                         if ((ob->ipo) || (ob->action)) {
1481                                 if (ob->ipo) {
1482                                         cks->ipo= ob->ipo;
1483                                 }
1484                                 else {
1485                                         bActionChannel *achan;
1486                                         
1487                                         cks->act= ob->action;
1488                                         achan= get_action_channel(ob->action, cks->actname);
1489                                         
1490                                         if (achan && achan->ipo)
1491                                                 cks->ipo= achan->ipo;
1492                                 }
1493                                 /* cks->ipo can be NULL while editing */
1494                                 if(cks->ipo) {
1495                                         /* deselect all ipo-curves */
1496                                         for (icu= cks->ipo->curve.first; icu; icu= icu->next) {
1497                                                 icu->flag &= ~IPO_SELECT;
1498                                         }
1499                                 }
1500                         }
1501                 }
1502                 CTX_DATA_END;
1503         }
1504 }
1505
1506 /* helper for commonkey_context_get() -  get keyingsets for buttons window */
1507 static void commonkey_context_getsbuts (const bContext *C, ListBase *sources, bKeyingContext **ksc)
1508 {
1509 #if 0 // XXX dunno what's the future of this stuff...   
1510         bCommonKeySrc *cks;
1511         
1512         /* check on tab-type */
1513         switch (G.buts->mainb) {
1514         case CONTEXT_SHADING:   /* ------------- Shading buttons ---------------- */
1515                 /* subtabs include "Material", "Texture", "Lamp", "World"*/
1516                 switch (G.buts->tab[CONTEXT_SHADING]) {
1517                         case TAB_SHADING_MAT: /* >------------- Material Tab -------------< */
1518                         {
1519                                 Material *ma= editnode_get_active_material(G.buts->lockpoin);
1520                                 
1521                                 if (ma) {
1522                                         /* add new keyframing destination */
1523                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1524                                         BLI_addtail(sources, cks); 
1525                                         
1526                                         /* set data */
1527                                         cks->id= (ID *)ma;
1528                                         cks->ipo= ma->ipo;
1529                                         cks->map= texchannel_to_adrcode(ma->texact);
1530                                         
1531                                         /* set keyingsets */
1532                                         *ksc= &ks_contexts[KSC_BUTS_MAT];
1533                                         return;
1534                                 }
1535                         }
1536                                 break;
1537                         case TAB_SHADING_WORLD: /* >------------- World Tab -------------< */
1538                         {
1539                                 World *wo= G.buts->lockpoin;
1540                                 
1541                                 if (wo) {
1542                                         /* add new keyframing destination */
1543                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1544                                         BLI_addtail(sources, cks); 
1545                                         
1546                                         /* set data */
1547                                         cks->id= (ID *)wo;
1548                                         cks->ipo= wo->ipo;
1549                                         cks->map= texchannel_to_adrcode(wo->texact);
1550                                         
1551                                         /* set keyingsets */
1552                                         *ksc= &ks_contexts[KSC_BUTS_WO];
1553                                         return;
1554                                 }
1555                         }
1556                                 break;
1557                         case TAB_SHADING_LAMP: /* >------------- Lamp Tab -------------< */
1558                         {
1559                                 Lamp *la= G.buts->lockpoin;
1560                                 
1561                                 if (la) {
1562                                         /* add new keyframing destination */
1563                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1564                                         BLI_addtail(sources, cks); 
1565                                         
1566                                         /* set data */
1567                                         cks->id= (ID *)la;
1568                                         cks->ipo= la->ipo;
1569                                         cks->map= texchannel_to_adrcode(la->texact);
1570                                         
1571                                         /* set keyingsets */
1572                                         *ksc= &ks_contexts[KSC_BUTS_LA];
1573                                         return;
1574                                 }
1575                         }
1576                                 break;
1577                         case TAB_SHADING_TEX: /* >------------- Texture Tab -------------< */
1578                         {
1579                                 Tex *tex= G.buts->lockpoin;
1580                                 
1581                                 if (tex) {
1582                                         /* add new keyframing destination */
1583                                         cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1584                                         BLI_addtail(sources, cks); 
1585                                         
1586                                         /* set data */
1587                                         cks->id= (ID *)tex;
1588                                         cks->ipo= tex->ipo;
1589                                         
1590                                         /* set keyingsets */
1591                                         *ksc= &ks_contexts[KSC_BUTS_TEX];
1592                                         return;
1593                                 }
1594                         }
1595                                 break;
1596                 }
1597                 break;
1598         
1599         case CONTEXT_OBJECT:    /* ------------- Object buttons ---------------- */
1600                 {
1601                         Object *ob= OBACT;
1602                         
1603                         if (ob) {
1604                                 /* add new keyframing destination */
1605                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1606                                 BLI_addtail(sources, cks);
1607                                 
1608                                 /* set id-block to key to */
1609                                 cks->id= (ID *)ob;
1610                                 cks->ipo= ob->ipo;
1611                                 
1612                                 /* set keyingsets */
1613                                 *ksc= &ks_contexts[KSC_BUTS_OB];
1614                                 return;
1615                         }
1616                 }
1617                 break;
1618         
1619         case CONTEXT_EDITING:   /* ------------- Editing buttons ---------------- */
1620                 {
1621                         Object *ob= OBACT;
1622                         
1623                         if ((ob) && (ob->type==OB_CAMERA) && (G.buts->lockpoin)) { /* >---------------- camera buttons ---------------< */
1624                                 Camera *ca= G.buts->lockpoin;
1625                                 
1626                                 /* add new keyframing destination */
1627                                 cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
1628                                 BLI_addtail(sources, cks);
1629                                 
1630                                 /* set id-block to key to */
1631                                 cks->id= (ID *)ca;
1632                                 cks->ipo= ca->ipo;
1633                                 
1634                                 /* set keyingsets */
1635                                 *ksc= &ks_contexts[KSC_BUTS_CAM];
1636                                 return;
1637                         }
1638                 }
1639                 break;
1640         }
1641 #endif // XXX end of buttons stuff to port...
1642         
1643         /* if nothing happened... */
1644         *ksc= NULL;
1645 }
1646
1647
1648 /* get keyingsets for appropriate context */
1649 static void commonkey_context_get (const bContext *C, ScrArea *sa, short mode, ListBase *sources, bKeyingContext **ksc)
1650 {
1651         /* get current view if no view is defined */
1652         if (sa == NULL)
1653                 sa= CTX_wm_area(C);
1654         
1655         /* check view type */
1656         switch (sa->spacetype) {
1657                 /* 3d view - first one tested as most often used */
1658                 case SPACE_VIEW3D:
1659                 {
1660                         commonkey_context_getv3d(C, sources, ksc);
1661                 }
1662                         break;
1663                         
1664                 /* buttons view */
1665                 case SPACE_BUTS:
1666                 {
1667                         commonkey_context_getsbuts(C, sources, ksc);
1668                 }
1669                         break;
1670                         
1671                 /* spaces with their own methods */
1672                 case SPACE_IPO:
1673                         //if (mode == COMMONKEY_MODE_INSERT)
1674                         //      insertkey_editipo(); // XXX old calls...
1675                         return;
1676                 case SPACE_ACTION:
1677                         //if (mode == COMMONKEY_MODE_INSERT)
1678                         //      insertkey_action(); // XXX old calls...
1679                         return;
1680                         
1681                 /* timeline view - keyframe buttons */
1682                 case SPACE_TIME:
1683                 {
1684                         bScreen *sc= CTX_wm_screen(C);
1685                         ScrArea *sab;
1686                         int bigarea= 0;
1687                         
1688                         /* try to find largest 3d-view available 
1689                          * (mostly of the time, this is what when user will want this,
1690                          *  as it's a standard feature in all other apps) 
1691                          */
1692                         //sab= find_biggest_area_of_type(SPACE_VIEW3D);
1693                         sab= NULL; // XXX for now...
1694                         if (sab) {
1695                                 commonkey_context_getv3d(C, sources, ksc);
1696                                 return;
1697                         }
1698                         
1699                         /* if not found, sab is now NULL, so perform own biggest area test */
1700                         for (sa= sc->areabase.first; sa; sa= sa->next) { // XXX this has changed!
1701                                 int area= sa->winx * sa->winy;
1702                                 
1703                                 if (sa->spacetype != SPACE_TIME) {
1704                                         if ( (!sab) || (area > bigarea) ) {
1705                                                 sab= sa;
1706                                                 bigarea= area;
1707                                         }
1708                                 }
1709                         }
1710                         
1711                         /* use whichever largest area was found (it shouldn't be a time window) */
1712                         if (sab)
1713                                 commonkey_context_get(C, sab, mode, sources, ksc);
1714                 }
1715                         break;
1716         }
1717 }
1718
1719 /* flush updates after all operations */
1720 static void commonkey_context_finish (const bContext *C, ListBase *sources)
1721 {
1722         ScrArea *curarea= CTX_wm_area(C);
1723         Scene *scene= CTX_data_scene(C);
1724         
1725         /* check view type */
1726         switch (curarea->spacetype) {
1727                 /* 3d view - first one tested as most often used */
1728                 case SPACE_VIEW3D:
1729                 {
1730                         /* either pose or object level */
1731                         if (OBACT && (OBACT->pose)) {   
1732                                 //Object *ob= OBACT;
1733                                 
1734                                 /* recalculate ipo handles, etc. */
1735                                 // XXX this method has been removed!
1736                                 //if (ob->action)
1737                                 //      remake_action_ipos(ob->action);
1738                                 
1739                                 /* recalculate bone-paths on adding new keyframe? */
1740                                 // XXX missing function
1741                                 // TODO: currently, there is no setting to turn this on/off globally
1742                                 //if (ob->pose->flag & POSE_RECALCPATHS)
1743                                 //      pose_recalculate_paths(ob);
1744                         }
1745                         else {
1746                                 bCommonKeySrc *cks;
1747                                 
1748                                 /* loop over bases (as seen in sources) */
1749                                 for (cks= sources->first; cks; cks= cks->next) {
1750                                         Object *ob= (Object *)cks->id;
1751                                         
1752                                         /* simply set recalc flag */
1753                                         ob->recalc |= OB_RECALC_OB;
1754                                 }
1755                         }
1756                 }
1757                         break;
1758         }
1759 }
1760
1761 /* flush refreshes after undo */
1762 static void commonkey_context_refresh (bContext *C)
1763 {
1764         ScrArea *curarea= CTX_wm_area(C);
1765         
1766         /* check view type */
1767         switch (curarea->spacetype) {
1768                 /* 3d view - first one tested as most often used */
1769                 case SPACE_VIEW3D:
1770                 {
1771                         /* do refreshes */
1772                         ED_anim_dag_flush_update(C);
1773                 }
1774                         break;
1775                         
1776                 /* buttons window */
1777                 case SPACE_BUTS:
1778                 {
1779                         //allspace(REMAKEIPO, 0);
1780                         //allqueue(REDRAWVIEW3D, 0);
1781                         //allqueue(REDRAWMARKER, 0);
1782                 }
1783                         break;
1784         }
1785 }
1786
1787 /* --- */
1788
1789 /* Build menu-string of available keying-sets (allocates memory for string)
1790  * NOTE: mode must not be longer than 64 chars
1791  */
1792 static char *build_keyingsets_menu (bKeyingContext *ksc, const char mode[48])
1793 {
1794         DynStr *pupds= BLI_dynstr_new();
1795         bKeyingSet *ks;
1796         char buf[64];
1797         char *str;
1798         int i, n;
1799         
1800         /* add title first */
1801         BLI_snprintf(buf, 64, "%s Key %%t|", mode);
1802         BLI_dynstr_append(pupds, buf);
1803         
1804         /* loop through keyingsets, adding them */
1805         for (ks=ksc->keyingsets, i=0, n=1; i < ksc->tot; ks++, i++, n++) {
1806                 /* check if keyingset can be used */
1807                 if (ks->flag == -1) {
1808                         /* optional separator? */
1809                         if (ks->include_cb) {
1810                                 if (ks->include_cb(ks, mode)) {
1811                                         BLI_snprintf( buf, 64, "%s%s", ks->name, ((n < ksc->tot)?"|":"") );
1812                                         BLI_dynstr_append(pupds, buf);
1813                                 }
1814                         }
1815                         else {
1816                                 BLI_snprintf( buf, 64, "%%l%s", ((n < ksc->tot)?"|":"") );
1817                                 BLI_dynstr_append(pupds, buf);
1818                         }
1819                 }
1820                 else if ( (ks->include_cb==NULL) || (ks->include_cb(ks, mode)) ) {
1821                         /* entry can be included */
1822                         BLI_dynstr_append(pupds, ks->name);
1823                         
1824                         /* check if special "shapekey" entry */
1825                         if (ks->flag == -3)
1826                                 BLI_snprintf( buf, 64, "%%x0%s", ((n < ksc->tot)?"|":"") );
1827                         else
1828                                 BLI_snprintf( buf, 64, "%%x%d%s", n, ((n < ksc->tot)?"|":"") );
1829                         BLI_dynstr_append(pupds, buf);
1830                 }
1831         }
1832         
1833         /* convert to normal MEM_malloc'd string */
1834         str= BLI_dynstr_get_cstring(pupds);
1835         BLI_dynstr_free(pupds);
1836         
1837         return str;
1838 }
1839
1840 /* Get the keying set that was chosen by the user from the menu */
1841 static bKeyingSet *get_keyingset_fromcontext (bKeyingContext *ksc, short index)
1842 {
1843         /* check if index is valid */
1844         if (ELEM(NULL, ksc, ksc->keyingsets))
1845                 return NULL;
1846         if ((index < 1) || (index > ksc->tot))
1847                 return NULL;
1848                 
1849         /* index starts from 1, and should directly correspond to keyingset in array */
1850         return (bKeyingSet *)(ksc->keyingsets + (index - 1));
1851 }
1852
1853 /* ---------------- Keyframe Management API -------------------- */
1854
1855 /* Display a menu for handling the insertion of keyframes based on the active view */
1856 void common_modifykey (bContext *C, short mode)
1857 {
1858         ListBase dsources = {NULL, NULL};
1859         bKeyingContext *ksc= NULL;
1860         bCommonKeySrc *cks;
1861         bKeyingSet *ks = NULL;
1862         char *menustr, buf[64];
1863         short menu_nr;
1864         
1865         /* check if mode is valid */
1866         if (ELEM(mode, COMMONKEY_MODE_INSERT, COMMONKEY_MODE_DELETE)==0)
1867                 return;
1868         
1869         /* delegate to other functions or get keyingsets to use 
1870          *      - if the current area doesn't have its own handling, there will be data returned...
1871          */
1872         commonkey_context_get(C, NULL, mode, &dsources, &ksc);
1873         
1874         /* check that there is data to operate on */
1875         if (ELEM(NULL, dsources.first, ksc)) {
1876                 BLI_freelistN(&dsources);
1877                 return;
1878         }
1879         
1880         /* get menu and process it */
1881         if (mode == COMMONKEY_MODE_DELETE)
1882                 menustr= build_keyingsets_menu(ksc, "Delete");
1883         else
1884                 menustr= build_keyingsets_menu(ksc, "Insert");
1885         // XXX: this goes to the invoke!
1886         //menu_nr= pupmenu(menustr);
1887         //if (menustr) MEM_freeN(menustr);
1888         menu_nr = -1; // XXX for now
1889         
1890         /* no item selected or shapekey entry? */
1891         if (menu_nr < 1) {
1892                 /* free temp sources */
1893                 BLI_freelistN(&dsources);
1894                 
1895                 /* check if insert new shapekey */
1896                 // XXX missing function!
1897                 //if ((menu_nr == 0) && (mode == COMMONKEY_MODE_INSERT))
1898                 //      insert_shapekey(OBACT);
1899                 //else 
1900                         ksc->lastused= NULL;
1901                         
1902                 return;
1903         }
1904         else {
1905                 /* try to get keyingset */
1906                 ks= get_keyingset_fromcontext(ksc, menu_nr);
1907                 
1908                 if (ks == NULL) {
1909                         BLI_freelistN(&dsources);
1910                         return;
1911                 }
1912         }
1913         
1914         /* loop over each destination, applying the keying set */
1915         for (cks= dsources.first; cks; cks= cks->next) {
1916                 short success= 0;
1917                 
1918                 /* special hacks for 'available' option */
1919                 if (ks->flag == -2) {
1920                         IpoCurve *icu= NULL, *icn= NULL;
1921                         
1922                         /* get first IPO-curve */
1923                         if (cks->act && cks->actname) {
1924                                 bActionChannel *achan= get_action_channel(cks->act, cks->actname);
1925                                 
1926                                 // FIXME: what about constraint channels?
1927                                 if (achan && achan->ipo)
1928                                         icu= achan->ipo->curve.first; 
1929                         }
1930                         else if(cks->ipo)
1931                                 icu= cks->ipo->curve.first;
1932                                 
1933                         /* we get adrcodes directly from IPO curves (see method below...) */
1934                         for (; icu; icu= icn) {
1935                                 short flag;
1936                                 
1937                                 /* get next ipo-curve in case current is deleted */
1938                                 icn= icu->next;
1939                                 
1940                                 /* insert mode or delete mode */
1941                                 if (mode == COMMONKEY_MODE_DELETE) {
1942                                         /* local flags only add on to global flags */
1943                                         flag = 0;
1944                                         
1945                                         /* delete keyframe */
1946                                         success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
1947                                 }
1948                                 else {
1949                                         /* local flags only add on to global flags */
1950                                         flag = ks->flag;
1951                                         if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
1952                                         if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
1953                                         // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
1954                                         
1955                                         /* insert keyframe */
1956                                         success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
1957                                 }
1958                         }
1959                 }
1960                 else {
1961                         bKS_AdrcodeGetter kag;
1962                         short (*get_next_adrcode)(bKS_AdrcodeGetter *);
1963                         int adrcode;
1964                         
1965                         /* initialise keyingset channel iterator */
1966                         ks_adrcodegetter_init(&kag, ks, cks);
1967                         
1968                         /* get iterator - only one can be in use at a time... the flags should be mutually exclusive in this regard */
1969                         if (ks->flag & COMMONKEY_PCHANROT)
1970                                 get_next_adrcode= ks_getnextadrcode_pchanrot;
1971                         else if (ks->flag & COMMONKEY_ADDMAP)
1972                                 get_next_adrcode= ks_getnextadrcode_addmap;
1973                         else
1974                                 get_next_adrcode= ks_getnextadrcode_default;
1975                         
1976                         /* loop over channels available in keyingset */
1977                         for (adrcode= get_next_adrcode(&kag); adrcode > 0; adrcode= get_next_adrcode(&kag)) {
1978                                 short flag;
1979                                 
1980                                 /* insert mode or delete mode */
1981                                 if (mode == COMMONKEY_MODE_DELETE) {
1982                                         /* local flags only add on to global flags */
1983                                         flag = 0;
1984                                         //flag &= ~COMMONKEY_MODES;
1985                                         
1986                                         /* delete keyframe */
1987                                         success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
1988                                 }
1989                                 else {
1990                                         /* local flags only add on to global flags */
1991                                         flag = ks->flag;
1992                                         if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
1993                                         if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
1994                                         // if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
1995                                         flag &= ~COMMONKEY_MODES;
1996                                         
1997                                         /* insert keyframe */
1998                                         success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
1999                                 }
2000                         }
2001                 }
2002                 
2003                 /* special handling for some key-sources */
2004                 if (success) {
2005                         /* set pose recalc-paths flag */
2006                         if (cks->pchan) {
2007                                 Object *ob= (Object *)cks->id;
2008                                 bPoseChannel *pchan= cks->pchan;
2009                                 
2010                                 /* set flag to trigger path recalc */
2011                                 if (pchan->path) 
2012                                         ob->pose->flag |= POSE_RECALCPATHS;
2013                                         
2014                                 /* clear unkeyed flag (it doesn't matter if it's set or not) */
2015                                         // XXX old animation system
2016                                 //if (pchan->bone)
2017                                 //      pchan->bone->flag &= ~BONE_UNKEYED;
2018                         }
2019                         
2020                         // XXX for new system, need to remove overrides
2021                 }
2022         }
2023         
2024         /* apply post-keying flushes for this data sources */
2025         commonkey_context_finish(C, &dsources);
2026         
2027         /* free temp data */
2028         BLI_freelistN(&dsources);
2029         
2030         /* queue updates for contexts */
2031         commonkey_context_refresh(C);
2032 }
2033
2034 #endif // XXX old keyingsets code based on adrcodes... to be restored in due course
2035
2036 /* Insert Key Operator ------------------------ */
2037
2038 /* XXX WARNING:
2039  * This is currently just a basic operator, which work in 3d-view context on objects/bones only
2040  * and will insert keyframes for a few settings only. This is until it becomes clear how
2041  * to separate (or not) the process for RNA-path creation between context + keyingsets.
2042  * 
2043  * -- Joshua Leung, Jan 2009
2044  */
2045
2046 /* defines for basic insert-key testing operator  */
2047         // XXX this will definitely be replaced
2048 EnumPropertyItem prop_insertkey_types[] = {
2049         {0, "OBLOC", "Object Location", ""},
2050         {1, "OBROT", "Object Rotation", ""},
2051         {2, "OBSCALE", "Object Scale", ""},
2052         {3, "MAT_COL", "Active Material - Color", ""},
2053         {4, "PCHANLOC", "Pose-Channel Location", ""},
2054         {5, "PCHANROT", "Pose-Channel Rotation", ""},
2055         {6, "PCHANSCALE", "Pose-Channel Scale", ""},
2056         {0, NULL, NULL, NULL}
2057 };
2058  
2059 static int insert_key_exec (bContext *C, wmOperator *op)
2060 {
2061         Scene *scene= CTX_data_scene(C);
2062         short mode= RNA_enum_get(op->ptr, "type");
2063         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2064         
2065         // XXX more comprehensive tests will be needed
2066         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2067         {
2068                 Object *ob= base->object;
2069                 ID *id= (ID *)ob;
2070                 short success= 0;
2071                 
2072                 /* check which keyframing mode chosen for this object */
2073                 if (mode < 4) {
2074                         /* object-based keyframes */
2075                         switch (mode) {
2076                         case 3: /* color of active material (only for geometry...) */
2077                                 // NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same
2078                                 // XXX no group for now
2079                                 success+= insertkey(id, NULL, "active_material.diffuse_color", 0, cfra, 0);
2080                                 success+= insertkey(id, NULL, "active_material.diffuse_color", 1, cfra, 0);
2081                                 success+= insertkey(id, NULL, "active_material.diffuse_color", 2, cfra, 0);
2082                                 break;
2083                         case 2: /* object scale */
2084                                 success+= insertkey(id, "Object Transforms", "scale", 0, cfra, 0);
2085                                 success+= insertkey(id, "Object Transforms", "scale", 1, cfra, 0);
2086                                 success+= insertkey(id, "Object Transforms", "scale", 2, cfra, 0);
2087                                 break;
2088                         case 1: /* object rotation */
2089                                 success+= insertkey(id, "Object Transforms", "rotation", 0, cfra, 0);
2090                                 success+= insertkey(id, "Object Transforms", "rotation", 1, cfra, 0);
2091                                 success+= insertkey(id, "Object Transforms", "rotation", 2, cfra, 0);
2092                                 break;
2093                         default: /* object location */
2094                                 success+= insertkey(id, "Object Transforms", "location", 0, cfra, 0);
2095                                 success+= insertkey(id, "Object Transforms", "location", 1, cfra, 0);
2096                                 success+= insertkey(id, "Object Transforms", "location", 2, cfra, 0);
2097                                 break;
2098                         }
2099                         
2100                         ob->recalc |= OB_RECALC_OB;
2101                 }
2102                 else if ((ob->pose) && (ob->flag & OB_POSEMODE)) {
2103                         /* PoseChannel based keyframes */
2104                         bPoseChannel *pchan;
2105                         
2106                         for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
2107                                 /* only if selected */
2108                                 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
2109                                         char buf[512];
2110                                         
2111                                         switch (mode) {
2112                                         case 6: /* pchan scale */
2113                                                 sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name);
2114                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2115                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2116                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2117                                                 break;
2118                                         case 5: /* pchan rotation */
2119                                                 if (pchan->rotmode == PCHAN_ROT_QUAT) {
2120                                                         sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name);
2121                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2122                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2123                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2124                                                         success+= insertkey(id, pchan->name, buf, 3, cfra, 0);
2125                                                 }
2126                                                 else {
2127                                                         sprintf(buf, "pose.pose_channels[\"%s\"].euler_rotation", pchan->name);
2128                                                         success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2129                                                         success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2130                                                         success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2131                                                 }
2132                                                 break;
2133                                         default: /* pchan location */
2134                                                 sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name);
2135                                                 success+= insertkey(id, pchan->name, buf, 0, cfra, 0);
2136                                                 success+= insertkey(id, pchan->name, buf, 1, cfra, 0);
2137                                                 success+= insertkey(id, pchan->name, buf, 2, cfra, 0);
2138                                                 break;
2139                                         }
2140                                 }
2141                         }
2142                         
2143                         ob->recalc |= OB_RECALC_OB;
2144                 }
2145                 
2146                 printf("Ob '%s' - Successfully added %d Keyframes \n", id->name+2, success);
2147         }
2148         CTX_DATA_END;
2149         
2150         /* send updates */
2151         ED_anim_dag_flush_update(C);    
2152         
2153         if (mode == 3) // material color requires different notifiers
2154                 WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, NULL);
2155         else
2156                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2157         
2158         return OPERATOR_FINISHED;
2159 }
2160
2161 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
2162 {
2163         PropertyRNA *prop;
2164         
2165         /* identifiers */
2166         ot->name= "Insert Keyframe";
2167         ot->idname= "ANIM_OT_insert_keyframe";
2168         
2169         /* callbacks */
2170         ot->invoke= WM_menu_invoke; // XXX we will need our own one eventually, to cope with the dynamic menus...
2171         ot->exec= insert_key_exec; 
2172         ot->poll= ED_operator_areaactive;
2173         
2174         /* flags */
2175         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2176         
2177         /* properties */
2178                 // XXX update this for the latest RNA stuff styles...
2179         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
2180         RNA_def_property_enum_items(prop, prop_insertkey_types);
2181 }
2182
2183 /* Delete Key Operator ------------------------ */
2184
2185 /* XXX WARNING:
2186  * This is currently just a basic operator, which work in 3d-view context on objects only. 
2187  * -- Joshua Leung, Jan 2009
2188  */
2189  
2190 static int delete_key_exec (bContext *C, wmOperator *op)
2191 {
2192         Scene *scene= CTX_data_scene(C);
2193         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
2194         
2195         // XXX more comprehensive tests will be needed
2196         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
2197         {
2198                 Object *ob= base->object;
2199                 ID *id= (ID *)ob;
2200                 FCurve *fcu, *fcn;
2201                 short success= 0;
2202                 
2203                 /* loop through all curves in animdata and delete keys on this frame */
2204                 if (ob->adt) {
2205                         AnimData *adt= ob->adt;
2206                         bAction *act= adt->action;
2207                         
2208                         for (fcu= act->curves.first; fcu; fcu= fcn) {
2209                                 fcn= fcu->next;
2210                                 success+= deletekey(id, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
2211                         }
2212                 }
2213                 
2214                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
2215                 
2216                 ob->recalc |= OB_RECALC_OB;
2217         }
2218         CTX_DATA_END;
2219         
2220         /* send updates */
2221         ED_anim_dag_flush_update(C);    
2222         
2223                 // XXX what if it was a material keyframe?
2224         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
2225         
2226         return OPERATOR_FINISHED;
2227 }
2228
2229 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
2230 {
2231         /* identifiers */
2232         ot->name= "Delete Keyframe";
2233         ot->idname= "ANIM_OT_delete_keyframe";
2234         
2235         /* callbacks */
2236         ot->invoke= WM_operator_confirm; // XXX we will need our own one eventually, to cope with the dynamic menus...
2237         ot->exec= delete_key_exec; 
2238         
2239         ot->poll= ED_operator_areaactive;
2240         
2241         /* flags */
2242         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2243 }
2244
2245 /* ******************************************* */
2246 /* KEYFRAME DETECTION */
2247
2248 /* --------------- API/Per-Datablock Handling ------------------- */
2249
2250 /* Checks whether an IPO-block has a keyframe for a given frame 
2251  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
2252  */
2253 short action_frame_has_keyframe (bAction *act, float frame, short filter)
2254 {
2255         FCurve *fcu;
2256         
2257         /* can only find if there is data */
2258         if (act == NULL)
2259                 return 0;
2260                 
2261         /* if only check non-muted, check if muted */
2262         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
2263                 return 0;
2264         
2265         /* loop over F-Curves, using binary-search to try to find matches 
2266          *      - this assumes that keyframes are only beztriples
2267          */
2268         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
2269                 /* only check if there are keyframes (currently only of type BezTriple) */
2270                 if (fcu->bezt) {
2271                         /* we either include all regardless of muting, or only non-muted  */
2272                         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
2273                                 short replace = -1;
2274                                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
2275                                 
2276                                 /* binarysearch_bezt_index will set replace to be 0 or 1
2277                                  *      - obviously, 1 represents a match
2278                                  */
2279                                 if (replace) {                  
2280                                         /* sanity check: 'i' may in rare cases exceed arraylen */
2281                                         if ((i >= 0) && (i < fcu->totvert))
2282                                                 return 1;
2283                                 }
2284                         }
2285                 }
2286         }
2287         
2288         /* nothing found */
2289         return 0;
2290 }
2291
2292 /* Checks whether an Object has a keyframe for a given frame */
2293 short object_frame_has_keyframe (Object *ob, float frame, short filter)
2294 {
2295         /* error checking */
2296         if (ob == NULL)
2297                 return 0;
2298         
2299         /* check own animation data - specifically, the action it contains */
2300         if ((ob->adt) && (ob->adt->action)) {
2301                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
2302                         return 1;
2303         }
2304         
2305         /* try shapekey keyframes (if available, and allowed by filter) */
2306         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
2307                 Key *key= ob_get_key(ob);
2308                 
2309                 /* shapekeys can have keyframes ('Relative Shape Keys') 
2310                  * or depend on time (old 'Absolute Shape Keys') 
2311                  */
2312                  
2313                         /* 1. test for relative (with keyframes) */
2314                 if (id_frame_has_keyframe((ID *)key, frame, filter))
2315                         return 1;
2316                         
2317                         /* 2. test for time */
2318                 // TODO... yet to be implemented (this feature may evolve before then anyway)
2319         }
2320         
2321         /* try materials */
2322         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
2323                 /* if only active, then we can skip a lot of looping */
2324                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
2325                         Material *ma= give_current_material(ob, (ob->actcol + 1));
2326                         
2327                         /* we only retrieve the active material... */
2328                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
2329                                 return 1;
2330                 }
2331                 else {
2332                         int a;
2333                         
2334                         /* loop over materials */
2335                         for (a=0; a<ob->totcol; a++) {
2336                                 Material *ma= give_current_material(ob, a+1);
2337                                 
2338                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
2339                                         return 1;
2340                         }
2341                 }
2342         }
2343         
2344         /* nothing found */
2345         return 0;
2346 }
2347
2348 /* --------------- API ------------------- */
2349
2350 /* Checks whether a keyframe exists for the given ID-block one the given frame */
2351 short id_frame_has_keyframe (ID *id, float frame, short filter)
2352 {
2353         /* sanity checks */
2354         if (id == NULL)
2355                 return 0;
2356         
2357         /* perform special checks for 'macro' types */
2358         switch (GS(id->name)) {
2359                 case ID_OB: /* object */
2360                         return object_frame_has_keyframe((Object *)id, frame, filter);
2361                         break;
2362                         
2363                 case ID_SCE: /* scene */
2364                 // XXX TODO... for now, just use 'normal' behaviour
2365                 //      break;
2366                 
2367                 default:        /* 'normal type' */
2368                 {
2369                         AnimData *adt= BKE_animdata_from_id(id);
2370                         
2371                         /* only check keyframes in active action */
2372                         if (adt)
2373                                 return action_frame_has_keyframe(adt->action, frame, filter);
2374                 }
2375                         break;
2376         }
2377         
2378         
2379         /* no keyframe found */
2380         return 0;
2381 }
2382
2383 /* ************************************************** */