Undo revision 23130 which was a merge with 2.5, a messy one because I did something...
[blender.git] / source / blender / editors / animation / keyframing.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_dynstr.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51 #include "DNA_windowmanager_types.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_constraint.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_nla.h"
58 #include "BKE_global.h"
59 #include "BKE_utildefines.h"
60 #include "BKE_context.h"
61 #include "BKE_report.h"
62 #include "BKE_key.h"
63 #include "BKE_material.h"
64
65 #include "ED_anim_api.h"
66 #include "ED_keyframing.h"
67 #include "ED_keyframes_edit.h"
68 #include "ED_screen.h"
69 #include "ED_util.h"
70
71 #include "UI_interface.h"
72
73 #include "WM_api.h"
74 #include "WM_types.h"
75
76 #include "RNA_access.h"
77 #include "RNA_define.h"
78 #include "RNA_types.h"
79
80 #include "anim_intern.h"
81
82 /* ******************************************* */
83 /* Animation Data Validation */
84
85 /* Get (or add relevant data to be able to do so) the Active Action for the given 
86  * Animation Data block, given an ID block where the Animation Data should reside.
87  */
88 bAction *verify_adt_action (ID *id, short add)
89 {
90         AnimData *adt;
91         
92         /* init animdata if none available yet */
93         adt= BKE_animdata_from_id(id);
94         if ((adt == NULL) && (add))
95                 adt= BKE_id_add_animdata(id);
96         if (adt == NULL) { 
97                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
98                 printf("ERROR: Couldn't add AnimData (ID = %s) \n", (id) ? (id->name) : "<None>");
99                 return NULL;
100         }
101                 
102         /* init action if none available yet */
103         // TODO: need some wizardry to handle NLA stuff correct
104         if ((adt->action == NULL) && (add))
105                 adt->action= add_empty_action("Action");
106                 
107         /* return the action */
108         return adt->action;
109 }
110
111 /* Get (or add relevant data to be able to do so) F-Curve from the Active Action, 
112  * for the given Animation Data block. This assumes that all the destinations are valid.
113  */
114 FCurve *verify_fcurve (bAction *act, const char group[], const char rna_path[], const int array_index, short add)
115 {
116         bActionGroup *grp;
117         FCurve *fcu;
118         
119         /* sanity checks */
120         if ELEM(NULL, act, rna_path)
121                 return NULL;
122                 
123         /* try to find f-curve matching for this setting 
124          *      - add if not found and allowed to add one
125          *              TODO: add auto-grouping support? how this works will need to be resolved
126          */
127         if (act)
128                 fcu= list_find_fcurve(&act->curves, rna_path, array_index);
129         else
130                 fcu= NULL;
131         
132         if ((fcu == NULL) && (add)) {
133                 /* use default settings to make a F-Curve */
134                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
135                 
136                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
137                 if (act->curves.first==NULL) 
138                         fcu->flag |= FCURVE_ACTIVE;     /* first one added active */
139                         
140                 /* store path - make copy, and store that */
141                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
142                 fcu->array_index= array_index;
143                 
144                 /* if a group name has been provided, try to add or find a group, then add F-Curve to it */
145                 if (group) {
146                         /* try to find group */
147                         grp= action_groups_find_named(act, group);
148                         
149                         /* no matching groups, so add one */
150                         if (grp == NULL) {
151                                 /* Add a new group, and make it active */
152                                 grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
153                                 
154                                 grp->flag = AGRP_SELECTED;
155                                 BLI_snprintf(grp->name, 64, group);
156                                 
157                                 BLI_addtail(&act->groups, grp);
158                                 BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
159                         }
160                         
161                         /* add F-Curve to group */
162                         action_groups_add_channel(act, grp, fcu);
163                 }
164                 else {
165                         /* just add F-Curve to end of Action's list */
166                         BLI_addtail(&act->curves, fcu);
167                 }
168         }
169         
170         /* return the F-Curve */
171         return fcu;
172 }
173
174 /* ************************************************** */
175 /* KEYFRAME INSERTION */
176
177 /* -------------- BezTriple Insertion -------------------- */
178
179 /* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
180 #define BEZT_INSERT_THRESH      0.00001f
181
182 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
183  * Returns the index to insert at (data already at that index will be offset if replace is 0)
184  */
185 static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
186 {
187         int start=0, end=arraylen;
188         int loopbreaker= 0, maxloop= arraylen * 2;
189         
190         /* initialise replace-flag first */
191         *replace= 0;
192         
193         /* sneaky optimisations (don't go through searching process if...):
194          *      - keyframe to be added is to be added out of current bounds
195          *      - keyframe to be added would replace one of the existing ones on bounds
196          */
197         if ((arraylen <= 0) || (array == NULL)) {
198                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
199                 return 0;
200         }
201         else {
202                 /* check whether to add before/after/on */
203                 float framenum;
204                 
205                 /* 'First' Keyframe (when only one keyframe, this case is used) */
206                 framenum= array[0].vec[1][0];
207                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
208                         *replace = 1;
209                         return 0;
210                 }
211                 else if (frame < framenum)
212                         return 0;
213                         
214                 /* 'Last' Keyframe */
215                 framenum= array[(arraylen-1)].vec[1][0];
216                 if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
217                         *replace= 1;
218                         return (arraylen - 1);
219                 }
220                 else if (frame > framenum)
221                         return arraylen;
222         }
223         
224         
225         /* most of the time, this loop is just to find where to put it
226          * 'loopbreaker' is just here to prevent infinite loops 
227          */
228         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
229                 /* compute and get midpoint */
230                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
231                 float midfra= array[mid].vec[1][0];
232                 
233                 /* check if exactly equal to midpoint */
234                 if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
235                         *replace = 1;
236                         return mid;
237                 }
238                 
239                 /* repeat in upper/lower half */
240                 if (frame > midfra)
241                         start= mid + 1;
242                 else if (frame < midfra)
243                         end= mid - 1;
244         }
245         
246         /* print error if loop-limit exceeded */
247         if (loopbreaker == (maxloop-1)) {
248                 printf("Error: binarysearch_bezt_index() was taking too long \n");
249                 
250                 // include debug info 
251                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
252         }
253         
254         /* not found, so return where to place it */
255         return start;
256 }
257
258 /* This function adds a given BezTriple to an F-Curve. It will allocate 
259  * memory for the array if needed, and will insert the BezTriple into a
260  * suitable place in chronological order.
261  * 
262  * NOTE: any recalculate of the F-Curve that needs to be done will need to 
263  *              be done by the caller.
264  */
265 int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt)
266 {
267         BezTriple *newb;
268         int i= 0;
269         
270         if (fcu->bezt) {
271                 short replace = -1;
272                 i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace);
273                 
274                 if (replace) {                  
275                         /* sanity check: 'i' may in rare cases exceed arraylen */
276                         // FIXME: do not overwrite handletype if just replacing...?
277                         if ((i >= 0) && (i < fcu->totvert))
278                                 *(fcu->bezt + i) = *bezt;
279                 }
280                 else {
281                         /* add new */
282                         newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple");
283                         
284                         /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
285                         if (i > 0)
286                                 memcpy(newb, fcu->bezt, i*sizeof(BezTriple));
287                         
288                         /* add beztriple to paste at index i */
289                         *(newb + i)= *bezt;
290                         
291                         /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
292                         if (i < fcu->totvert) 
293                                 memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple));
294                         
295                         /* replace (+ free) old with new */
296                         MEM_freeN(fcu->bezt);
297                         fcu->bezt= newb;
298                         
299                         fcu->totvert++;
300                 }
301         }
302         else {
303                 // TODO: need to check for old sample-data now...
304                 fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
305                 *(fcu->bezt)= *bezt;
306                 fcu->totvert= 1;
307         }
308         
309         
310         /* we need to return the index, so that some tools which do post-processing can 
311          * detect where we added the BezTriple in the array
312          */
313         return i;
314 }
315
316 /* This function is a wrapper for insert_bezt_icu, and should be used when
317  * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
318  * else yet. 
319  * 
320  * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
321  */
322 void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast)
323 {
324         BezTriple beztr;
325         int a;
326         
327         /* set all three points, for nicer start position */
328         memset(&beztr, 0, sizeof(BezTriple));
329         beztr.vec[0][0]= x; 
330         beztr.vec[0][1]= y;
331         beztr.vec[1][0]= x;
332         beztr.vec[1][1]= y;
333         beztr.vec[2][0]= x;
334         beztr.vec[2][1]= y;
335         beztr.ipo= U.ipo_new; /* use default interpolation mode here... */
336         beztr.f1= beztr.f2= beztr.f3= SELECT;
337         beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one?
338         
339         /* add temp beztriple to keyframes */
340         a= insert_bezt_fcurve(fcu, &beztr);
341         
342         /* what if 'a' is a negative index? 
343          * for now, just exit to prevent any segfaults
344          */
345         if (a < 0) return;
346         
347         /* don't recalculate handles if fast is set
348          *      - this is a hack to make importers faster
349          *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
350          */
351         if (!fast) calchandles_fcurve(fcu);
352         
353         /* set handletype and interpolation */
354         if (fcu->totvert > 2) {
355                 BezTriple *bezt= (fcu->bezt + a);
356                 char h1, h2;
357                 
358                 /* set handles (autohandles by default) */
359                 h1= h2= HD_AUTO;
360                 
361                 if (a > 0) h1= (bezt-1)->h2;
362                 if (a < fcu->totvert-1) h2= (bezt+1)->h1;
363                 
364                 bezt->h1= h1;
365                 bezt->h2= h2;
366                 
367                 /* set interpolation from previous (if available) */
368                 if (a > 0) bezt->ipo= (bezt-1)->ipo;
369                 else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo;
370                         
371                 /* don't recalculate handles if fast is set
372                  *      - this is a hack to make importers faster
373                  *      - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations)
374                  */
375                 if (!fast) calchandles_fcurve(fcu);
376         }
377 }
378
379 /* -------------- 'Smarter' Keyframing Functions -------------------- */
380 /* return codes for new_key_needed */
381 enum {
382         KEYNEEDED_DONTADD = 0,
383         KEYNEEDED_JUSTADD,
384         KEYNEEDED_DELPREV,
385         KEYNEEDED_DELNEXT
386 } eKeyNeededStatus;
387
388 /* This helper function determines whether a new keyframe is needed */
389 /* Cases where keyframes should not be added:
390  *      1. Keyframe to be added bewteen two keyframes with similar values
391  *      2. Keyframe to be added on frame where two keyframes are already situated
392  *      3. Keyframe lies at point that intersects the linear line between two keyframes
393  */
394 static short new_key_needed (FCurve *fcu, float cFrame, float nValue) 
395 {
396         BezTriple *bezt=NULL, *prev=NULL;
397         int totCount, i;
398         float valA = 0.0f, valB = 0.0f;
399         
400         /* safety checking */
401         if (fcu == NULL) return KEYNEEDED_JUSTADD;
402         totCount= fcu->totvert;
403         if (totCount == 0) return KEYNEEDED_JUSTADD;
404         
405         /* loop through checking if any are the same */
406         bezt= fcu->bezt;
407         for (i=0; i<totCount; i++) {
408                 float prevPosi=0.0f, prevVal=0.0f;
409                 float beztPosi=0.0f, beztVal=0.0f;
410                         
411                 /* get current time+value */    
412                 beztPosi= bezt->vec[1][0];
413                 beztVal= bezt->vec[1][1];
414                         
415                 if (prev) {
416                         /* there is a keyframe before the one currently being examined */               
417                         
418                         /* get previous time+value */
419                         prevPosi= prev->vec[1][0];
420                         prevVal= prev->vec[1][1];
421                         
422                         /* keyframe to be added at point where there are already two similar points? */
423                         if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
424                                 return KEYNEEDED_DONTADD;
425                         }
426                         
427                         /* keyframe between prev+current points ? */
428                         if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
429                                 /* is the value of keyframe to be added the same as keyframes on either side ? */
430                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
431                                         return KEYNEEDED_DONTADD;
432                                 }
433                                 else {
434                                         float realVal;
435                                         
436                                         /* get real value of curve at that point */
437                                         realVal= evaluate_fcurve(fcu, cFrame);
438                                         
439                                         /* compare whether it's the same as proposed */
440                                         if (IS_EQ(realVal, nValue)) 
441                                                 return KEYNEEDED_DONTADD;
442                                         else 
443                                                 return KEYNEEDED_JUSTADD;
444                                 }
445                         }
446                         
447                         /* new keyframe before prev beztriple? */
448                         if (cFrame < prevPosi) {
449                                 /* A new keyframe will be added. However, whether the previous beztriple
450                                  * stays around or not depends on whether the values of previous/current
451                                  * beztriples and new keyframe are the same.
452                                  */
453                                 if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
454                                         return KEYNEEDED_DELNEXT;
455                                 else 
456                                         return KEYNEEDED_JUSTADD;
457                         }
458                 }
459                 else {
460                         /* just add a keyframe if there's only one keyframe 
461                          * and the new one occurs before the exisiting one does.
462                          */
463                         if ((cFrame < beztPosi) && (totCount==1))
464                                 return KEYNEEDED_JUSTADD;
465                 }
466                 
467                 /* continue. frame to do not yet passed (or other conditions not met) */
468                 if (i < (totCount-1)) {
469                         prev= bezt;
470                         bezt++;
471                 }
472                 else
473                         break;
474         }
475         
476         /* Frame in which to add a new-keyframe occurs after all other keys
477          * -> If there are at least two existing keyframes, then if the values of the
478          *       last two keyframes and the new-keyframe match, the last existing keyframe
479          *       gets deleted as it is no longer required.
480          * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
481          *       keyframe is not equal to last keyframe.
482          */
483         bezt= (fcu->bezt + (fcu->totvert - 1));
484         valA= bezt->vec[1][1];
485         
486         if (prev)
487                 valB= prev->vec[1][1];
488         else 
489                 valB= bezt->vec[1][1] + 1.0f; 
490                 
491         if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) 
492                 return KEYNEEDED_DELPREV;
493         else 
494                 return KEYNEEDED_JUSTADD;
495 }
496
497 /* ------------------ RNA Data-Access Functions ------------------ */
498
499 /* Try to read value using RNA-properties obtained already */
500 static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index)
501 {
502         float value= 0.0f;
503         
504         switch (RNA_property_type(prop)) {
505                 case PROP_BOOLEAN:
506                         if (RNA_property_array_length(prop))
507                                 value= (float)RNA_property_boolean_get_index(ptr, prop, index);
508                         else
509                                 value= (float)RNA_property_boolean_get(ptr, prop);
510                         break;
511                 case PROP_INT:
512                         if (RNA_property_array_length(prop))
513                                 value= (float)RNA_property_int_get_index(ptr, prop, index);
514                         else
515                                 value= (float)RNA_property_int_get(ptr, prop);
516                         break;
517                 case PROP_FLOAT:
518                         if (RNA_property_array_length(prop))
519                                 value= RNA_property_float_get_index(ptr, prop, index);
520                         else
521                                 value= RNA_property_float_get(ptr, prop);
522                         break;
523                 case PROP_ENUM:
524                         value= (float)RNA_property_enum_get(ptr, prop);
525                         break;
526                 default:
527                         break;
528         }
529         
530         return value;
531 }
532
533 /* ------------------ 'Visual' Keyframing Functions ------------------ */
534
535 /* internal status codes for visualkey_can_use */
536 enum {
537         VISUALKEY_NONE = 0,
538         VISUALKEY_LOC,
539         VISUALKEY_ROT,
540 };
541
542 /* This helper function determines if visual-keyframing should be used when  
543  * inserting keyframes for the given channel. As visual-keyframing only works
544  * on Object and Pose-Channel blocks, this should only get called for those 
545  * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying 
546  * settings is on.
547  */
548 static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop)
549 {
550         bConstraint *con= NULL;
551         short searchtype= VISUALKEY_NONE;
552         char *identifier= NULL;
553         
554         /* validate data */
555         // TODO: this check is probably not needed, but it won't hurt
556         if (ELEM3(NULL, ptr, ptr->data, prop))
557                 return 0;
558                 
559         /* get first constraint and determine type of keyframe constraints to check for 
560          *      - constraints can be on either Objects or PoseChannels, so we only check if the
561          *        ptr->type is RNA_Object or RNA_PoseChannel, which are the RNA wrapping-info for
562          *        those structs, allowing us to identify the owner of the data 
563          */
564         if (ptr->type == &RNA_Object) {
565                 /* Object */
566                 Object *ob= (Object *)ptr->data;
567                 
568                 con= ob->constraints.first;
569                 identifier= (char *)RNA_property_identifier(prop);
570         }
571         else if (ptr->type == &RNA_PoseChannel) {
572                 /* Pose Channel */
573                 bPoseChannel *pchan= (bPoseChannel *)ptr->data;
574                 
575                 con= pchan->constraints.first;
576                 identifier= (char *)RNA_property_identifier(prop);
577         }
578         
579         /* check if any data to search using */
580         if (ELEM(NULL, con, identifier))
581                 return 0;
582                 
583         /* location or rotation identifiers only... */
584         if (strstr(identifier, "location"))
585                 searchtype= VISUALKEY_LOC;
586         else if (strstr(identifier, "rotation"))
587                 searchtype= VISUALKEY_ROT;
588         else {
589                 printf("visualkey_can_use() failed: identifier - '%s' \n", identifier);
590                 return 0;
591         }
592         
593         
594         /* only search if a searchtype and initial constraint are available */
595         if (searchtype && con) {
596                 for (; con; con= con->next) {
597                         /* only consider constraint if it is not disabled, and has influence */
598                         if (con->flag & CONSTRAINT_DISABLE) continue;
599                         if (con->enforce == 0.0f) continue;
600                         
601                         /* some constraints may alter these transforms */
602                         switch (con->type) {
603                                 /* multi-transform constraints */
604                                 case CONSTRAINT_TYPE_CHILDOF:
605                                         return 1;
606                                 case CONSTRAINT_TYPE_TRANSFORM:
607                                         return 1;
608                                 case CONSTRAINT_TYPE_FOLLOWPATH:
609                                         return 1;
610                                 case CONSTRAINT_TYPE_KINEMATIC:
611                                         return 1;
612                                         
613                                 /* single-transform constraits  */
614                                 case CONSTRAINT_TYPE_TRACKTO:
615                                         if (searchtype==VISUALKEY_ROT) return 1;
616                                         break;
617                                 case CONSTRAINT_TYPE_ROTLIMIT:
618                                         if (searchtype==VISUALKEY_ROT) return 1;
619                                         break;
620                                 case CONSTRAINT_TYPE_LOCLIMIT:
621                                         if (searchtype==VISUALKEY_LOC) return 1;
622                                         break;
623                                 case CONSTRAINT_TYPE_ROTLIKE:
624                                         if (searchtype==VISUALKEY_ROT) return 1;
625                                         break;
626                                 case CONSTRAINT_TYPE_DISTLIMIT:
627                                         if (searchtype==VISUALKEY_LOC) return 1;
628                                         break;
629                                 case CONSTRAINT_TYPE_LOCLIKE:
630                                         if (searchtype==VISUALKEY_LOC) return 1;
631                                         break;
632                                 case CONSTRAINT_TYPE_LOCKTRACK:
633                                         if (searchtype==VISUALKEY_ROT) return 1;
634                                         break;
635                                 case CONSTRAINT_TYPE_MINMAX:
636                                         if (searchtype==VISUALKEY_LOC) return 1;
637                                         break;
638                                 
639                                 default:
640                                         break;
641                         }
642                 }
643         }
644         
645         /* when some condition is met, this function returns, so here it can be 0 */
646         return 0;
647 }
648
649 /* This helper function extracts the value to use for visual-keyframing 
650  * In the event that it is not possible to perform visual keying, try to fall-back
651  * to using the default method. Assumes that all data it has been passed is valid.
652  */
653 static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index)
654 {
655         char *identifier= (char *)RNA_property_identifier(prop);
656         
657         /* handle for Objects or PoseChannels only 
658          *      - constraints can be on either Objects or PoseChannels, so we only check if the
659          *        ptr->type is RNA_Object or RNA_PoseChannel, which are the RNA wrapping-info for
660          *        those structs, allowing us to identify the owner of the data 
661          *      - assume that array_index will be sane
662          */
663         if (ptr->type == &RNA_Object) {
664                 Object *ob= (Object *)ptr->data;
665                 
666                 /* parented objects are not supported, as the effects of the parent
667                  * are included in the matrix, which kindof beats the point
668                  */
669                 if (ob->parent == NULL) {
670                         /* only Location or Rotation keyframes are supported now */
671                         if (strstr(identifier, "location")) {
672                                 return ob->obmat[3][array_index];
673                         }
674                         else if (strstr(identifier, "rotation")) {
675                                 float eul[3];
676                                 
677                                 Mat4ToEul(ob->obmat, eul);
678                                 return eul[array_index];
679                         }
680                 }
681         }
682         else if (ptr->type == &RNA_PoseChannel) {
683                 Object *ob= (Object *)ptr->id.data; /* we assume that this is always set, and is an object */
684                 bPoseChannel *pchan= (bPoseChannel *)ptr->data;
685                 float tmat[4][4];
686                 
687                 /* Although it is not strictly required for this particular space conversion, 
688                  * arg1 must not be null, as there is a null check for the other conversions to
689                  * be safe. Therefore, the active object is passed here, and in many cases, this
690                  * will be what owns the pose-channel that is getting this anyway.
691                  */
692                 Mat4CpyMat4(tmat, pchan->pose_mat);
693                 constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
694                 
695                 /* Loc, Rot/Quat keyframes are supported... */
696                 if (strstr(identifier, "location")) {
697                         /* only use for non-connected bones */
698                         if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
699                                 return tmat[3][array_index];
700                         else if (pchan->bone->parent == NULL)
701                                 return tmat[3][array_index];
702                 }
703                 else if (strstr(identifier, "euler_rotation")) {
704                         float eul[3];
705                         
706                         /* euler-rotation test before standard rotation, as standard rotation does quats */
707                         Mat4ToEul(tmat, eul);
708                         return eul[array_index];
709                 }
710                 else if (strstr(identifier, "rotation")) {
711                         float trimat[3][3], quat[4];
712                         
713                         Mat3CpyMat4(trimat, tmat);
714                         Mat3ToQuat_is_ok(trimat, quat);
715                         
716                         return quat[array_index];
717                 }
718         }
719         
720         /* as the function hasn't returned yet, read value from system in the default way */
721         return setting_get_rna_value(ptr, prop, array_index);
722 }
723
724 /* ------------------------- Insert Key API ------------------------- */
725
726 /* Secondary Keyframing API call: 
727  *      Use this when validation of necessary animation data is not necessary, since an RNA-pointer to the necessary
728  *      data being keyframed, and a pointer to the F-Curve to use have both been provided.
729  *
730  *      The flag argument is used for special settings that alter the behaviour of
731  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
732  *      and extra keyframe filtering.
733  */
734 short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
735 {
736         float curval= 0.0f;
737         
738         /* no F-Curve to add keyframe to? */
739         if (fcu == NULL) {
740                 printf("ERROR: no F-Curve to add keyframes to \n");
741                 return 0;
742         }
743         
744         /* if no property given yet, try to validate from F-Curve info */
745         if ((ptr.id.data == NULL) && (ptr.data==NULL)) {
746                 printf("ERROR: no RNA-pointer available to retrieve values for keyframing from\n");
747                 return 0;
748         }
749         if (prop == NULL) {
750                 PointerRNA tmp_ptr;
751                 
752                 /* try to get property we should be affecting */
753                 if ((RNA_path_resolve(&ptr, fcu->rna_path, &tmp_ptr, &prop) == 0) || (prop == NULL)) {
754                         /* property not found... */
755                         char *idname= (ptr.id.data) ? ((ID *)ptr.id.data)->name : "<No ID-Pointer>";
756                         
757                         printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", idname, fcu->rna_path);
758                         return 0;
759                 }
760                 else {
761                         /* property found, so overwrite 'ptr' to make later code easier */
762                         ptr= tmp_ptr;
763                 }
764         }
765         
766         /* set additional flags for the F-Curve (i.e. only integer values) */
767         fcu->flag &= ~(FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);
768         switch (RNA_property_type(prop)) {
769                 case PROP_FLOAT:
770                         /* do nothing */
771                         break;
772                 case PROP_INT:
773                         /* do integer (only 'whole' numbers) interpolation between all points */
774                         fcu->flag |= FCURVE_INT_VALUES;
775                         break;
776                 default:
777                         /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
778                          * values at all) interpolation between all points
779                          *      - however, we must also ensure that evaluated values are only integers still
780                          */
781                         fcu->flag |= (FCURVE_DISCRETE_VALUES|FCURVE_INT_VALUES);
782                         break;
783         }
784         
785         /* obtain value to give keyframe */
786         if ( (flag & INSERTKEY_MATRIX) && 
787                  (visualkey_can_use(&ptr, prop)) ) 
788         {
789                 /* visual-keying is only available for object and pchan datablocks, as 
790                  * it works by keyframing using a value extracted from the final matrix 
791                  * instead of using the kt system to extract a value.
792                  */
793                 curval= visualkey_get_value(&ptr, prop, fcu->array_index);
794         }
795         else {
796                 /* read value from system */
797                 curval= setting_get_rna_value(&ptr, prop, fcu->array_index);
798         }
799         
800         /* only insert keyframes where they are needed */
801         if (flag & INSERTKEY_NEEDED) {
802                 short insert_mode;
803                 
804                 /* check whether this curve really needs a new keyframe */
805                 insert_mode= new_key_needed(fcu, cfra, curval);
806                 
807                 /* insert new keyframe at current frame */
808                 if (insert_mode)
809                         insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
810                 
811                 /* delete keyframe immediately before/after newly added */
812                 switch (insert_mode) {
813                         case KEYNEEDED_DELPREV:
814                                 delete_fcurve_key(fcu, fcu->totvert-2, 1);
815                                 break;
816                         case KEYNEEDED_DELNEXT:
817                                 delete_fcurve_key(fcu, 1, 1);
818                                 break;
819                 }
820                 
821                 /* only return success if keyframe added */
822                 if (insert_mode)
823                         return 1;
824         }
825         else {
826                 /* just insert keyframe */
827                 insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
828                 
829                 /* return success */
830                 return 1;
831         }
832         
833         /* failed */
834         return 0;
835 }
836
837 /* Main Keyframing API call:
838  *      Use this when validation of necessary animation data is necessary, since it may not exist yet.
839  *      
840  *      The flag argument is used for special settings that alter the behaviour of
841  *      the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
842  *      and extra keyframe filtering.
843  */
844 short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
845 {       
846         PointerRNA id_ptr, ptr;
847         PropertyRNA *prop;
848         FCurve *fcu;
849         
850         /* validate pointer first - exit if failure */
851         RNA_id_pointer_create(id, &id_ptr);
852         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
853                 printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
854                 return 0;
855         }
856         
857         /* get F-Curve - if no action is provided, keyframe to the default one attached to this ID-block */
858         if (act == NULL) {
859                 AnimData *adt= BKE_animdata_from_id(id);
860                 
861                 /* get action to add F-Curve+keyframe to */
862                 act= verify_adt_action(id, 1);
863                 
864                 /* apply NLA-mapping to frame to use (if applicable) */
865                 cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
866         }
867         fcu= verify_fcurve(act, group, rna_path, array_index, 1);
868         
869         /* apply special time tweaking */
870                 // XXX check on this stuff...
871         if (GS(id->name) == ID_OB) {
872                 //Object *ob= (Object *)id;
873                 
874                 /* ancient time-offset cruft */
875                 //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
876                 //      /* actually frametofloat calc again! */
877                 //      cfra-= give_timeoffset(ob)*scene->r.framelen;
878                 //}
879         }
880         
881         /* insert keyframe */
882         return insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
883 }
884
885 /* ************************************************** */
886 /* KEYFRAME DELETION */
887
888 /* Main Keyframing API call:
889  *      Use this when validation of necessary animation data isn't necessary as it
890  *      already exists. It will delete a keyframe at the current frame.
891  *      
892  *      The flag argument is used for special settings that alter the behaviour of
893  *      the keyframe deletion. These include the quick refresh options.
894  */
895 short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
896 {
897         FCurve *fcu = NULL;
898         
899         /* get F-Curve
900          * Note: here is one of the places where we don't want new Action + F-Curve added!
901          *              so 'add' var must be 0
902          */
903         if (act == NULL) {
904                 /* if no action is provided, use the default one attached to this ID-block */
905                 AnimData *adt= BKE_animdata_from_id(id);
906                 act= adt->action;
907                 
908                 /* apply NLA-mapping to frame to use (if applicable) */
909                 cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); 
910         }
911         /* we don't check the validity of the path here yet, but it should be ok... */
912         fcu= verify_fcurve(act, group, rna_path, array_index, 0);
913         
914         /* only continue if we have an F-Curve to remove keyframes from */
915         if (act && fcu) {
916                 short found = -1;
917                 int i;
918                 
919                 /* apply special time tweaking */
920                 if (GS(id->name) == ID_OB) {
921                         //Object *ob= (Object *)id;
922                         
923                         /* ancient time-offset cruft */
924                         //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
925                         //      /* actually frametofloat calc again! */
926                         //      cfra-= give_timeoffset(ob)*scene->r.framelen;
927                         //}
928                 }
929                 
930                 /* try to find index of beztriple to get rid of */
931                 i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
932                 if (found) {                    
933                         /* delete the key at the index (will sanity check + do recalc afterwards) */
934                         delete_fcurve_key(fcu, i, 1);
935                         
936                         /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */
937                         if (fcu->totvert == 0) {
938                                 BLI_remlink(&act->curves, fcu);
939                                 free_fcurve(fcu);
940                         }
941                         
942                         /* return success */
943                         return 1;
944                 }
945         }
946         
947         /* return failure */
948         return 0;
949 }
950
951 /* ******************************************* */
952 /* KEYFRAME MODIFICATION */
953
954 /* mode for commonkey_modifykey */
955 enum {
956         COMMONKEY_MODE_INSERT = 0,
957         COMMONKEY_MODE_DELETE,
958 } eCommonModifyKey_Modes;
959
960 /* Polling callback for use with ANIM_*_keyframe() operators
961  * This is based on the standard ED_operator_areaactive callback,
962  * except that it does special checks for a few spacetypes too...
963  */
964 static int modify_key_op_poll(bContext *C)
965 {
966         ScrArea *sa= CTX_wm_area(C);
967         Scene *scene= CTX_data_scene(C);
968         SpaceOops *so= CTX_wm_space_outliner(C);
969         
970         /* if no area or active scene */
971         if (ELEM(NULL, sa, scene)) 
972                 return 0;
973         
974         /* if Outliner, only allow in DataBlocks view */
975         if (so && (so->outlinevis != SO_DATABLOCKS))
976                 return 0;
977         
978         /* TODO: checks for other space types can be added here */
979         
980         /* should be fine */
981         return 1;
982 }
983
984 /* Insert Key Operator ------------------------ */
985
986 static int insert_key_exec (bContext *C, wmOperator *op)
987 {
988         ListBase dsources = {NULL, NULL};
989         Scene *scene= CTX_data_scene(C);
990         KeyingSet *ks= NULL;
991         int type= RNA_int_get(op->ptr, "type");
992         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
993         short success;
994         
995         /* type is the Keying Set the user specified to use when calling the operator:
996          *      - type == 0: use scene's active Keying Set
997          *      - type > 0: use a user-defined Keying Set from the active scene
998          *      - type < 0: use a builtin Keying Set
999          */
1000         if (type == 0) 
1001                 type= scene->active_keyingset;
1002         if (type > 0)
1003                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
1004         else
1005                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
1006                 
1007         /* report failures */
1008         if (ks == NULL) {
1009                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1010                 return OPERATOR_CANCELLED;
1011         }
1012         
1013         /* get context info for relative Keying Sets */
1014         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1015                 /* exit if no suitable data obtained */
1016                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
1017                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
1018                         return OPERATOR_CANCELLED;
1019                 }
1020         }
1021         
1022         /* try to insert keyframes for the channels specified by KeyingSet */
1023         success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
1024         printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
1025         
1026         /* report failure? */
1027         if (success == 0)
1028                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
1029         
1030         /* free temp context-data if available */
1031         if (dsources.first) {
1032                 /* we assume that there is no extra data that needs to be freed from here... */
1033                 BLI_freelistN(&dsources);
1034         }
1035         
1036         /* send updates */
1037         ED_anim_dag_flush_update(C);    
1038         
1039         /* for now, only send ND_KEYS for KeyingSets */
1040         WM_event_add_notifier(C, ND_KEYS, NULL);
1041         
1042         return OPERATOR_FINISHED;
1043 }
1044
1045 void ANIM_OT_insert_keyframe (wmOperatorType *ot)
1046 {
1047         /* identifiers */
1048         ot->name= "Insert Keyframe";
1049         ot->idname= "ANIM_OT_insert_keyframe";
1050         
1051         /* callbacks */
1052         ot->exec= insert_key_exec; 
1053         ot->poll= modify_key_op_poll;
1054         
1055         /* flags */
1056         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1057         
1058         /* settings */
1059         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1060 }
1061
1062 /* Insert Key Operator (With Menu) ------------------------ */
1063
1064 /* XXX 
1065  * This operator pops up a menu which sets gets the index of the keyingset to use,
1066  * setting the global settings, and calling the insert-keyframe operator using these
1067  * settings
1068  */
1069
1070 static int insert_key_menu_invoke (bContext *C, wmOperator *op, wmEvent *event)
1071 {
1072         Scene *scene= CTX_data_scene(C);
1073         KeyingSet *ks;
1074         uiPopupMenu *pup;
1075         uiLayout *layout;
1076         int i = 0;
1077         
1078         pup= uiPupMenuBegin(C, "Insert Keyframe", 0);
1079         layout= uiPupMenuLayout(pup);
1080         
1081         /* active Keying Set 
1082          *      - only include entry if it exists
1083          */
1084         if (scene->active_keyingset) {
1085                 uiItemIntO(layout, "Active Keying Set", 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1086                 uiItemS(layout);
1087         }
1088         else
1089                 i++;
1090         
1091         /* user-defined Keying Sets 
1092          *      - these are listed in the order in which they were defined for the active scene
1093          */
1094         if (scene->keyingsets.first) {
1095                 for (ks= scene->keyingsets.first; ks; ks= ks->next)
1096                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i++);
1097                 uiItemS(layout);
1098         }
1099         
1100         /* builtin Keying Sets */
1101         // XXX polling the entire list may lag
1102         i= -1;
1103         for (ks= builtin_keyingsets.first; ks; ks= ks->next) {
1104                 /* only show KeyingSet if context is suitable */
1105                 if (keyingset_context_ok_poll(C, ks)) {
1106                         uiItemIntO(layout, ks->name, 0, "ANIM_OT_insert_keyframe_menu", "type", i--);
1107                 }
1108         }
1109         
1110         uiPupMenuEnd(C, pup);
1111         
1112         return OPERATOR_CANCELLED;
1113 }
1114  
1115 void ANIM_OT_insert_keyframe_menu (wmOperatorType *ot)
1116 {
1117         /* identifiers */
1118         ot->name= "Insert Keyframe Menu";
1119         ot->idname= "ANIM_OT_insert_keyframe_menu";
1120         
1121         /* callbacks */
1122         ot->invoke= insert_key_menu_invoke;
1123         ot->exec= insert_key_exec; 
1124         ot->poll= ED_operator_areaactive;
1125         
1126         /* flags */
1127         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1128         
1129         /* properties
1130          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1131          */
1132         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1133 }
1134
1135 /* Delete Key Operator ------------------------ */
1136
1137 static int delete_key_exec (bContext *C, wmOperator *op)
1138 {
1139         ListBase dsources = {NULL, NULL};
1140         Scene *scene= CTX_data_scene(C);
1141         KeyingSet *ks= NULL;    
1142         int type= RNA_int_get(op->ptr, "type");
1143         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1144         short success;
1145         
1146         /* type is the Keying Set the user specified to use when calling the operator:
1147          *      - type == 0: use scene's active Keying Set
1148          *      - type > 0: use a user-defined Keying Set from the active scene
1149          *      - type < 0: use a builtin Keying Set
1150          */
1151         if (type == 0) 
1152                 type= scene->active_keyingset;
1153         if (type > 0)
1154                 ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
1155         else
1156                 ks= BLI_findlink(&builtin_keyingsets, -type-1);
1157         
1158         /* report failure */
1159         if (ks == NULL) {
1160                 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1161                 return OPERATOR_CANCELLED;
1162         }
1163         
1164         /* get context info for relative Keying Sets */
1165         if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1166                 /* exit if no suitable data obtained */
1167                 if (modifykey_get_context_data(C, &dsources, ks) == 0) {
1168                         BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
1169                         return OPERATOR_CANCELLED;
1170                 }
1171         }
1172         
1173         /* try to insert keyframes for the channels specified by KeyingSet */
1174         success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
1175         printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
1176         
1177         /* report failure? */
1178         if (success == 0)
1179                 BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
1180         
1181         /* free temp context-data if available */
1182         if (dsources.first) {
1183                 /* we assume that there is no extra data that needs to be freed from here... */
1184                 BLI_freelistN(&dsources);
1185         }
1186         
1187         /* send updates */
1188         ED_anim_dag_flush_update(C);    
1189         
1190         /* for now, only send ND_KEYS for KeyingSets */
1191         WM_event_add_notifier(C, ND_KEYS, NULL);
1192         
1193         return OPERATOR_FINISHED;
1194 }
1195
1196 void ANIM_OT_delete_keyframe (wmOperatorType *ot)
1197 {
1198         /* identifiers */
1199         ot->name= "Delete Keyframe";
1200         ot->idname= "ANIM_OT_delete_keyframe";
1201         
1202         /* callbacks */
1203         ot->exec= delete_key_exec; 
1204         ot->poll= modify_key_op_poll;
1205         
1206         /* flags */
1207         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1208         
1209         /* properties
1210          *      - NOTE: here the type is int not enum, since many of the indicies here are determined dynamically
1211          */
1212         RNA_def_int(ot->srna, "type", 0, INT_MIN, INT_MAX, "Keying Set Number", "Index (determined internally) of the Keying Set to use", 0, 1);
1213 }
1214
1215 /* Delete Key Operator ------------------------ */
1216
1217 /* XXX WARNING:
1218  * This is currently just a basic operator, which work in 3d-view context on objects only. 
1219  * Should this be kept? It does have advantages over a version which requires selecting a keyingset to use...
1220  * -- Joshua Leung, Jan 2009
1221  */
1222  
1223 static int delete_key_v3d_exec (bContext *C, wmOperator *op)
1224 {
1225         Scene *scene= CTX_data_scene(C);
1226         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1227         
1228         // XXX more comprehensive tests will be needed
1229         CTX_DATA_BEGIN(C, Base*, base, selected_bases) 
1230         {
1231                 Object *ob= base->object;
1232                 ID *id= (ID *)ob;
1233                 FCurve *fcu, *fcn;
1234                 short success= 0;
1235                 
1236                 /* loop through all curves in animdata and delete keys on this frame */
1237                 if (ob->adt) {
1238                         AnimData *adt= ob->adt;
1239                         bAction *act= adt->action;
1240                         
1241                         for (fcu= act->curves.first; fcu; fcu= fcn) {
1242                                 fcn= fcu->next;
1243                                 success+= delete_keyframe(id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0);
1244                         }
1245                 }
1246                 
1247                 printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success);
1248                 
1249                 ob->recalc |= OB_RECALC_OB;
1250         }
1251         CTX_DATA_END;
1252         
1253         /* send updates */
1254         ED_anim_dag_flush_update(C);    
1255         
1256         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
1257         
1258         return OPERATOR_FINISHED;
1259 }
1260
1261 void ANIM_OT_delete_keyframe_v3d (wmOperatorType *ot)
1262 {
1263         /* identifiers */
1264         ot->name= "Delete Keyframe";
1265         ot->idname= "ANIM_OT_delete_keyframe_v3d";
1266         
1267         /* callbacks */
1268         ot->invoke= WM_operator_confirm;
1269         ot->exec= delete_key_v3d_exec; 
1270         
1271         ot->poll= ED_operator_areaactive;
1272         
1273         /* flags */
1274         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1275 }
1276
1277
1278 /* Insert Key Button Operator ------------------------ */
1279
1280 static int insert_key_button_exec (bContext *C, wmOperator *op)
1281 {
1282         Scene *scene= CTX_data_scene(C);
1283         PointerRNA ptr;
1284         PropertyRNA *prop= NULL;
1285         char *path;
1286         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1287         short success= 0;
1288         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1289         
1290         /* try to insert keyframe using property retrieved from UI */
1291         memset(&ptr, 0, sizeof(PointerRNA));
1292         uiAnimContextProperty(C, &ptr, &prop, &index);
1293         
1294         if ((ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
1295                 path= RNA_path_from_ID_to_property(&ptr, prop);
1296                 
1297                 if (path) {
1298                         if (all) {
1299                                 length= RNA_property_array_length(prop);
1300                                 
1301                                 if(length) index= 0;
1302                                 else length= 1;
1303                         }
1304                         else
1305                                 length= 1;
1306                         
1307                         for (a=0; a<length; a++)
1308                                 success+= insert_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
1309                         
1310                         MEM_freeN(path);
1311                 }
1312                 else if (ptr.type == &RNA_NlaStrip) {
1313                         /* handle special vars for NLA-strips */
1314                         NlaStrip *strip= (NlaStrip *)ptr.data;
1315                         FCurve *fcu= list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
1316                         
1317                         success+= insert_keyframe_direct(ptr, prop, fcu, cfra, 0);
1318                 }
1319                 else {
1320                         if (G.f & G_DEBUG)
1321                                 printf("Button Insert-Key: no path to property \n");
1322                         BKE_report(op->reports, RPT_WARNING, "Failed to resolve path to property. Try using a Keying Set instead.");
1323                 }
1324         }
1325         else if (G.f & G_DEBUG) {
1326                 printf("ptr.data = %p, prop = %p,", ptr.data, prop);
1327                 if(prop)
1328                         printf("animateable = %d \n", RNA_property_animateable(&ptr, prop));
1329                 else
1330                         printf("animateable = NULL \n");
1331         }
1332         
1333         if (success) {
1334                 /* send updates */
1335                 ED_anim_dag_flush_update(C);    
1336                 
1337                 /* for now, only send ND_KEYS for KeyingSets */
1338                 WM_event_add_notifier(C, ND_KEYS, NULL);
1339         }
1340         
1341         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1342 }
1343
1344 void ANIM_OT_insert_keyframe_button (wmOperatorType *ot)
1345 {
1346         /* identifiers */
1347         ot->name= "Insert Keyframe (Buttons)";
1348         ot->idname= "ANIM_OT_insert_keyframe_button";
1349         
1350         /* callbacks */
1351         ot->exec= insert_key_button_exec; 
1352         ot->poll= modify_key_op_poll;
1353         
1354         /* flags */
1355         ot->flag= OPTYPE_UNDO;
1356
1357         /* properties */
1358         RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array.");
1359 }
1360
1361 /* Delete Key Button Operator ------------------------ */
1362
1363 static int delete_key_button_exec (bContext *C, wmOperator *op)
1364 {
1365         Scene *scene= CTX_data_scene(C);
1366         PointerRNA ptr;
1367         PropertyRNA *prop= NULL;
1368         char *path;
1369         float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
1370         short success= 0;
1371         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
1372         
1373         /* try to insert keyframe using property retrieved from UI */
1374         memset(&ptr, 0, sizeof(PointerRNA));
1375         uiAnimContextProperty(C, &ptr, &prop, &index);
1376
1377         if (ptr.data && prop) {
1378                 path= RNA_path_from_ID_to_property(&ptr, prop);
1379                 
1380                 if (path) {
1381                         if (all) {
1382                                 length= RNA_property_array_length(prop);
1383                                 
1384                                 if(length) index= 0;
1385                                 else length= 1;
1386                         }
1387                         else
1388                                 length= 1;
1389                         
1390                         for (a=0; a<length; a++)
1391                                 success+= delete_keyframe(ptr.id.data, NULL, NULL, path, index+a, cfra, 0);
1392                         
1393                         MEM_freeN(path);
1394                 }
1395                 else if (G.f & G_DEBUG)
1396                         printf("Button Delete-Key: no path to property \n");
1397         }
1398         else if (G.f & G_DEBUG) {
1399                 printf("ptr.data = %p, prop = %p \n", ptr.data, prop);
1400         }
1401         
1402         
1403         if(success) {
1404                 /* send updates */
1405                 ED_anim_dag_flush_update(C);    
1406                 
1407                 /* for now, only send ND_KEYS for KeyingSets */
1408                 WM_event_add_notifier(C, ND_KEYS, NULL);
1409         }
1410         
1411         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1412 }
1413
1414 void ANIM_OT_delete_keyframe_button (wmOperatorType *ot)
1415 {
1416         /* identifiers */
1417         ot->name= "Delete Keyframe (Buttons)";
1418         ot->idname= "ANIM_OT_delete_keyframe_button";
1419         
1420         /* callbacks */
1421         ot->exec= delete_key_button_exec; 
1422         ot->poll= modify_key_op_poll;
1423         
1424         /* flags */
1425         ot->flag= OPTYPE_UNDO;
1426
1427         /* properties */
1428         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyfames from all elements of the array.");
1429 }
1430
1431 /* ******************************************* */
1432 /* AUTO KEYFRAME */
1433
1434 int autokeyframe_cfra_can_key(Scene *scene, ID *id)
1435 {
1436         float cfra= (float)CFRA; // XXX for now, this will do
1437         
1438         /* only filter if auto-key mode requires this */
1439         if (IS_AUTOKEY_ON(scene) == 0)
1440                 return 0;
1441                 
1442         if (IS_AUTOKEY_MODE(scene, NORMAL)) {
1443                 /* can insert anytime we like... */
1444                 return 1;
1445         }
1446         else /* REPLACE */ {
1447                 /* for whole block - only key if there's a keyframe on that frame already
1448                  *      this is a valid assumption when we're blocking + tweaking
1449                  */
1450                 return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
1451         }
1452 }
1453
1454 /* ******************************************* */
1455 /* KEYFRAME DETECTION */
1456
1457 /* --------------- API/Per-Datablock Handling ------------------- */
1458
1459 /* Checks if some F-Curve has a keyframe for a given frame */
1460 short fcurve_frame_has_keyframe (FCurve *fcu, float frame, short filter)
1461 {
1462         /* quick sanity check */
1463         if (fcu == NULL)
1464                 return 0;
1465         
1466         /* we either include all regardless of muting, or only non-muted  */
1467         if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
1468                 short replace = -1;
1469                 int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
1470                 
1471                 /* binarysearch_bezt_index will set replace to be 0 or 1
1472                  *      - obviously, 1 represents a match
1473                  */
1474                 if (replace) {                  
1475                         /* sanity check: 'i' may in rare cases exceed arraylen */
1476                         if ((i >= 0) && (i < fcu->totvert))
1477                                 return 1;
1478                 }
1479         }
1480         
1481         return 0;
1482 }
1483
1484 /* Checks whether an Action has a keyframe for a given frame 
1485  * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
1486  */
1487 short action_frame_has_keyframe (bAction *act, float frame, short filter)
1488 {
1489         FCurve *fcu;
1490         
1491         /* can only find if there is data */
1492         if (act == NULL)
1493                 return 0;
1494                 
1495         /* if only check non-muted, check if muted */
1496         if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED))
1497                 return 0;
1498         
1499         /* loop over F-Curves, using binary-search to try to find matches 
1500          *      - this assumes that keyframes are only beztriples
1501          */
1502         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
1503                 /* only check if there are keyframes (currently only of type BezTriple) */
1504                 if (fcu->bezt && fcu->totvert) {
1505                         if (fcurve_frame_has_keyframe(fcu, frame, filter))
1506                                 return 1;
1507                 }
1508         }
1509         
1510         /* nothing found */
1511         return 0;
1512 }
1513
1514 /* Checks whether an Object has a keyframe for a given frame */
1515 short object_frame_has_keyframe (Object *ob, float frame, short filter)
1516 {
1517         /* error checking */
1518         if (ob == NULL)
1519                 return 0;
1520         
1521         /* check own animation data - specifically, the action it contains */
1522         if ((ob->adt) && (ob->adt->action)) {
1523                 if (action_frame_has_keyframe(ob->adt->action, frame, filter))
1524                         return 1;
1525         }
1526         
1527         /* try shapekey keyframes (if available, and allowed by filter) */
1528         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY) ) {
1529                 Key *key= ob_get_key(ob);
1530                 
1531                 /* shapekeys can have keyframes ('Relative Shape Keys') 
1532                  * or depend on time (old 'Absolute Shape Keys') 
1533                  */
1534                  
1535                         /* 1. test for relative (with keyframes) */
1536                 if (id_frame_has_keyframe((ID *)key, frame, filter))
1537                         return 1;
1538                         
1539                         /* 2. test for time */
1540                 // TODO... yet to be implemented (this feature may evolve before then anyway)
1541         }
1542         
1543         /* try materials */
1544         if ( !(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT) ) {
1545                 /* if only active, then we can skip a lot of looping */
1546                 if (filter & ANIMFILTER_KEYS_ACTIVE) {
1547                         Material *ma= give_current_material(ob, (ob->actcol + 1));
1548                         
1549                         /* we only retrieve the active material... */
1550                         if (id_frame_has_keyframe((ID *)ma, frame, filter))
1551                                 return 1;
1552                 }
1553                 else {
1554                         int a;
1555                         
1556                         /* loop over materials */
1557                         for (a=0; a<ob->totcol; a++) {
1558                                 Material *ma= give_current_material(ob, a+1);
1559                                 
1560                                 if (id_frame_has_keyframe((ID *)ma, frame, filter))
1561                                         return 1;
1562                         }
1563                 }
1564         }
1565         
1566         /* nothing found */
1567         return 0;
1568 }
1569
1570 /* --------------- API ------------------- */
1571
1572 /* Checks whether a keyframe exists for the given ID-block one the given frame */
1573 short id_frame_has_keyframe (ID *id, float frame, short filter)
1574 {
1575         /* sanity checks */
1576         if (id == NULL)
1577                 return 0;
1578         
1579         /* perform special checks for 'macro' types */
1580         switch (GS(id->name)) {
1581                 case ID_OB: /* object */
1582                         return object_frame_has_keyframe((Object *)id, frame, filter);
1583                         break;
1584                         
1585                 case ID_SCE: /* scene */
1586                 // XXX TODO... for now, just use 'normal' behaviour
1587                 //      break;
1588                 
1589                 default:        /* 'normal type' */
1590                 {
1591                         AnimData *adt= BKE_animdata_from_id(id);
1592                         
1593                         /* only check keyframes in active action */
1594                         if (adt)
1595                                 return action_frame_has_keyframe(adt->action, frame, filter);
1596                 }
1597                         break;
1598         }
1599         
1600         
1601         /* no keyframe found */
1602         return 0;
1603 }
1604
1605 /* ************************************************** */