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