Batch renaming some keyframe editing internals in preparation for more generic keyfra...
[blender.git] / source / blender / editors / animation / anim_draw.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "DNA_anim_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32 #include "BLI_math.h"
33
34 #include "BKE_context.h"
35 #include "BKE_nla.h"
36 #include "BKE_object.h"
37
38 #include "ED_anim_api.h"
39 #include "ED_keyframes_edit.h"
40
41 #include "RNA_access.h"
42
43 #include "BIF_gl.h"
44
45 #include "UI_interface.h"
46 #include "UI_resources.h"
47 #include "UI_view2d.h"
48
49 /* XXX */
50 extern void ui_rasterpos_safe(float x, float y, float aspect);
51
52 /* *************************************************** */
53 /* TIME CODE FORMATTING */
54
55 /* Generate timecode/frame number string and store in the supplied string 
56  *      - buffer: must be at least 13 chars long 
57  *      - power: special setting for View2D grid drawing, 
58  *        used to specify how detailed we need to be
59  *      - timecodes: boolean specifying whether timecodes or
60  *        frame numbers get drawn
61  *      - cfra: time in frames or seconds, consistent with the values shown by timecodes
62  */
63 // TODO: have this in kernel instead under scene?
64 void ANIM_timecode_string_from_frame (char *str, Scene *scene, int power, short timecodes, float cfra)
65 {
66         if (timecodes) {
67                 int hours=0, minutes=0, seconds=0, frames=0;
68                 float raw_seconds= cfra;
69                 char neg[2]= "";
70                 
71                 /* get cframes */
72                 if (cfra < 0) {
73                         /* correction for negative cfraues */
74                         sprintf(neg, "-");
75                         cfra = -cfra;
76                 }
77                 if (cfra >= 3600) {
78                         /* hours */
79                         /* XXX should we only display a single digit for hours since clips are 
80                          *         VERY UNLIKELY to be more than 1-2 hours max? However, that would 
81                          *         go against conventions...
82                          */
83                         hours= (int)cfra / 3600;
84                         cfra= (float)fmod(cfra, 3600);
85                 }
86                 if (cfra >= 60) {
87                         /* minutes */
88                         minutes= (int)cfra / 60;
89                         cfra= (float)fmod(cfra, 60);
90                 }
91                 if (power <= 0) {
92                         /* seconds + frames
93                          *      Frames are derived from 'fraction' of second. We need to perform some additional rounding
94                          *      to cope with 'half' frames, etc., which should be fine in most cases
95                          */
96                         seconds= (int)cfra;
97                         frames= (int)floor( ((cfra - seconds) * FPS) + 0.5f );
98                 }
99                 else {
100                         /* seconds (with pixel offset rounding) */
101                         seconds= (int)floor(cfra + 0.375f);
102                 }
103                 
104                 switch (U.timecode_style) {
105                         case USER_TIMECODE_MINIMAL: 
106                         {
107                                 /*      - In general, minutes and seconds should be shown, as most clips will be
108                                  *        within this length. Hours will only be included if relevant.
109                                  *      - Only show frames when zoomed in enough for them to be relevant 
110                                  *        (using separator of '+' for frames).
111                                  *        When showing frames, use slightly different display to avoid confusion with mm:ss format
112                                  */
113                                 if (power <= 0) {
114                                         /* include "frames" in display */
115                                         if (hours) sprintf(str, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
116                                         else if (minutes) sprintf(str, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
117                                         else sprintf(str, "%s%d+%02d", neg, seconds, frames);
118                                 }
119                                 else {
120                                         /* don't include 'frames' in display */
121                                         if (hours) sprintf(str, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
122                                         else sprintf(str, "%s%02d:%02d", neg, minutes, seconds);
123                                 }
124                         }
125                                 break;
126                                 
127                         case USER_TIMECODE_SMPTE_MSF:
128                         {
129                                 /* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
130                                 if (hours) sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
131                                 else sprintf(str, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
132                         }
133                                 break;
134                         
135                         case USER_TIMECODE_MILLISECONDS:
136                         {
137                                 /* reduced SMPTE. Instead of frames, milliseconds are shown */
138                                 int ms_dp= (power <= 0) ? (1 - power) : 1; /* precision of decimal part */
139                                 int s_pad= ms_dp+3;     /* to get 2 digit whole-number part for seconds display (i.e. 3 is for 2 digits + radix, on top of full length) */
140                                 
141                                 if (hours) sprintf(str, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, cfra);
142                                 else sprintf(str, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, cfra);
143                         }
144                                 break;
145                                 
146                         case USER_TIMECODE_SECONDS_ONLY:
147                         {
148                                 /* only show the original seconds display */
149                                 /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
150                                 if (power <= 0) sprintf(str, "%.*f", 1-power, raw_seconds);
151                                 else sprintf(str, "%d", (int)floor(raw_seconds + 0.375f));
152                         }
153                                 break;
154                         
155                         case USER_TIMECODE_SMPTE_FULL:
156                         default:
157                         {
158                                 /* full SMPTE format */
159                                 sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
160                         }
161                                 break;
162                 }
163         }
164         else {
165                 /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
166                 if (power <= 0) sprintf(str, "%.*f", 1-power, cfra);
167                 else sprintf(str, "%d", (int)floor(cfra + 0.375f));
168         }
169
170
171 /* *************************************************** */
172 /* CURRENT FRAME DRAWING */
173
174 /* Draw current frame number in a little green box beside the current frame indicator */
175 static void draw_cfra_number (Scene *scene, View2D *v2d, float cfra, short time)
176 {
177         float xscale, yscale, x, y;
178         char str[32] = "    t"; /* t is the character to start replacing from */
179         short slen;
180         
181         /* because the frame number text is subject to the same scaling as the contents of the view */
182         UI_view2d_getscale(v2d, &xscale, &yscale);
183         glScalef(1.0f/xscale, 1.0f, 1.0f);
184         
185         /* get timecode string 
186          *      - padding on str-buf passed so that it doesn't sit on the frame indicator
187          *      - power = 0, gives 'standard' behaviour for time
188          *        but power = 1 is required for frames (to get integer frames)
189          */
190         if (time)
191                 ANIM_timecode_string_from_frame(&str[4], scene, 0, time, FRA2TIME(cfra));
192         else    
193                 ANIM_timecode_string_from_frame(&str[4], scene, 1, time, cfra);
194         slen= (short)UI_GetStringWidth(str) - 1;
195         
196         /* get starting coordinates for drawing */
197         x= cfra * xscale;
198         y= 18;
199         
200         /* draw green box around/behind text */
201         UI_ThemeColorShade(TH_CFRAME, 0);
202         glRectf(x, y,  x+slen,  y+15);
203         
204         /* draw current frame number - black text */
205         UI_ThemeColor(TH_TEXT);
206         UI_DrawString(x-5, y+3, str);
207         
208         /* restore view transform */
209         glScalef(xscale, 1.0, 1.0);
210 }
211
212 /* General call for drawing current frame indicator in animation editor */
213 void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag)
214 {
215         Scene *scene= CTX_data_scene(C);
216         float vec[2];
217         
218         /* Draw a light green line to indicate current frame */
219         vec[0]= (float)(scene->r.cfra * scene->r.framelen);
220         
221         UI_ThemeColor(TH_CFRAME);
222         glLineWidth(2.0);
223         
224         glBegin(GL_LINE_STRIP);
225                 vec[1]= v2d->cur.ymin-500.0f;   /* XXX arbitrary... want it go to bottom */
226                 glVertex2fv(vec);
227                 
228                 vec[1]= v2d->cur.ymax;
229                 glVertex2fv(vec);
230         glEnd();
231         
232         /* Draw dark green line if slow-parenting/time-offset is enabled */
233         if (flag & DRAWCFRA_SHOW_TIMEOFS) {
234                 Object *ob= (scene->basact) ? (scene->basact->object) : 0;
235                 
236                 // XXX ob->ipoflag is depreceated!
237                 if ((ob) && (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0f)) {
238                         vec[0]-= give_timeoffset(ob); /* could avoid calling twice */
239                         
240                         UI_ThemeColorShade(TH_CFRAME, -30);
241                         
242                         glBegin(GL_LINE_STRIP);
243                                 /*vec[1]= v2d->cur.ymax;*/ // this is set already. this line is only included
244                                 glVertex2fv(vec);
245                                 
246                                 vec[1]= v2d->cur.ymin;
247                                 glVertex2fv(vec);
248                         glEnd();
249                 }
250         }
251         
252         glLineWidth(1.0);
253         
254         /* Draw current frame number in a little box */
255         if (flag & DRAWCFRA_SHOW_NUMBOX) {
256                 UI_view2d_view_orthoSpecial(C, v2d, 1);
257                 draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS));
258         }
259 }
260
261 /* *************************************************** */
262 /* PREVIEW RANGE 'CURTAINS' */
263 /* Note: 'Preview Range' tools are defined in anim_ops.c */
264
265 /* Draw preview range 'curtains' for highlighting where the animation data is */
266 void ANIM_draw_previewrange (const bContext *C, View2D *v2d)
267 {
268         Scene *scene= CTX_data_scene(C);
269         
270         /* only draw this if preview range is set */
271         if (PRVRANGEON) {
272                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
273                 glEnable(GL_BLEND);
274                 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
275                 
276                 /* only draw two separate 'curtains' if there's no overlap between them */
277                 if (PSFRA < PEFRA) {
278                         glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
279                         glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);     
280                 } 
281                 else {
282                         glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
283                 }
284                 
285                 glDisable(GL_BLEND);
286         }
287 }
288
289 /* *************************************************** */
290 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
291
292 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
293 // TODO: do not supply return this if the animdata tells us that there is no mapping to perform
294 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
295 {
296         /* sanity checks */
297         if (ac == NULL)
298                 return NULL;
299         
300         /* handling depends on the type of animation-context we've got */
301         if (ale)
302                 return ale->adt;
303         else
304                 return NULL;
305 }
306
307 /* ------------------- */
308
309 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
310 static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
311 {
312         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
313         AnimData *adt= (AnimData *)ked->data;
314         short only_keys= (short)ked->i1;
315         
316         /* adjust BezTriple handles only if allowed to */
317         if (only_keys == 0) {
318                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
319                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
320         }
321         
322         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
323         
324         return 0;
325 }
326
327 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
328 static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
329 {
330         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
331         AnimData *adt= (AnimData*)ked->data;
332         short only_keys= (short)ked->i1;
333         
334         /* adjust BezTriple handles only if allowed to */
335         if (only_keys == 0) {
336                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
337                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
338         }
339         
340         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
341         
342         return 0;
343 }
344
345
346 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve 
347  *      - restore = whether to map points back to non-mapped time 
348  *      - only_keys = whether to only adjust the location of the center point of beztriples
349  */
350 void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys)
351 {
352         KeyframeEditData ked;
353         KeyframeEditFunc map_cb;
354         
355         /* init edit data 
356          *      - AnimData is stored in 'data'
357          *      - only_keys is stored in 'i1'
358          */
359         memset(&ked, 0, sizeof(KeyframeEditData));
360         ked.data= (void *)adt;
361         ked.i1= (int)only_keys;
362         
363         /* get editing callback */
364         if (restore)
365                 map_cb= bezt_nlamapping_restore;
366         else
367                 map_cb= bezt_nlamapping_apply;
368         
369         /* apply to F-Curve */
370         ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL);
371 }
372
373 /* *************************************************** */
374 /* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
375
376 /* Get unit conversion factor for given ID + F-Curve */
377 float ANIM_unit_mapping_get_factor (Scene *scene, ID *id, FCurve *fcu, short restore)
378 {
379         /* sanity checks */
380         if (id && fcu && fcu->rna_path) 
381         {
382                 PointerRNA ptr, id_ptr;
383                 PropertyRNA *prop;
384                 
385                 /* get RNA property that F-Curve affects */
386                 RNA_id_pointer_create(id, &id_ptr);
387                 if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) 
388                 {
389                         /* rotations: radians <-> degrees? */
390                         if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION)
391                         {
392                                 /* if the radians flag is not set, default to using degrees which need conversions */
393                                 if ((scene) && (scene->unit.flag & USER_UNIT_ROT_RADIANS) == 0) {
394                                         if (restore)
395                                                 return M_PI / 180.0f;   /* degrees to radians */
396                                         else
397                                                 return 180.0f / M_PI;   /* radians to degrees */
398                                 }
399                         }
400                         
401                         // TODO: other rotation types here as necessary
402                 }
403         }
404         
405         /* no mapping needs to occur... */
406         return 1.0f;
407 }
408
409 /* ----------------------- */
410
411 /* helper function for ANIM_unit_mapping_apply_fcurve -> mapping callback for unit mapping */
412 static short bezt_unit_mapping_apply (KeyframeEditData *ked, BezTriple *bezt)
413 {
414         /* mapping factor is stored in f1, flags are stored in i1 */
415         short only_keys= (ked->i1 & ANIM_UNITCONV_ONLYKEYS);
416         short sel_vs= (ked->i1 & ANIM_UNITCONV_SELVERTS);
417         float fac= ked->f1;
418         
419         /* adjust BezTriple handles only if allowed to */
420         if (only_keys == 0) {
421                 if ((sel_vs==0) || (bezt->f1 & SELECT)) 
422                         bezt->vec[0][1] *= fac;
423                 if ((sel_vs==0) || (bezt->f3 & SELECT)) 
424                         bezt->vec[2][1] *= fac;
425         }
426         
427         if ((sel_vs == 0) || (bezt->f2 & SELECT))
428                 bezt->vec[1][1] *= fac;
429         
430         return 0;
431 }
432
433 /* Apply/Unapply units conversions to keyframes */
434 void ANIM_unit_mapping_apply_fcurve (Scene *scene, ID *id, FCurve *fcu, short flag)
435 {
436         KeyframeEditData ked;
437         KeyframeEditFunc sel_cb;
438         float fac;
439         
440         /* calculate mapping factor, and abort if nothing to change */
441         fac= ANIM_unit_mapping_get_factor(scene, id, fcu, (flag & ANIM_UNITCONV_RESTORE));
442         if (fac == 1.0f)
443                 return;
444         
445         /* init edit data 
446          *      - mapping factor is stored in f1
447          *      - flags are stored in 'i1'
448          */
449         memset(&ked, 0, sizeof(KeyframeEditData));
450         ked.f1= (float)fac;
451         ked.i1= (int)flag;
452         
453         /* only selected? */
454         if (flag & ANIM_UNITCONV_ONLYSEL)
455                 sel_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
456         else
457                 sel_cb= NULL;
458         
459         /* apply to F-Curve */
460         ANIM_fcurve_keyframes_loop(&ked, fcu, sel_cb, bezt_unit_mapping_apply, NULL);
461         
462         // FIXME: loop here for samples should be generalised
463         // TODO: only sel?
464         if (fcu->fpt) {
465                 FPoint *fpt;
466                 int i;
467                 
468                 for (i=0, fpt=fcu->fpt; i < fcu->totvert; i++, fpt++) {
469                         /* apply unit mapping */
470                         fpt->vec[1] *= fac;
471                 }
472         }
473 }
474
475 /* *************************************************** */