4a8557a2b1f63b8c4ea2598d0f4bdee94515bdf1
[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 "BLI_sys_types.h"
32
33 #include "DNA_anim_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_userdef_types.h"
37
38 #include "BLI_math.h"
39
40 #include "BKE_context.h"
41 #include "BKE_blender.h"
42 #include "BKE_global.h"
43 #include "BKE_nla.h"
44 #include "BKE_object.h"
45
46 #include "ED_anim_api.h"
47 #include "ED_keyframes_edit.h"
48
49 #include "RNA_access.h"
50
51 #include "BIF_gl.h"
52
53 #include "UI_interface.h"
54 #include "UI_resources.h"
55 #include "UI_view2d.h"
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 + GLA_PIXEL_OFS);
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                                 break;
130                         }
131                         case USER_TIMECODE_SMPTE_MSF:
132                         {
133                                 /* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
134                                 if (hours) sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
135                                 else sprintf(str, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
136                                 break;
137                         }
138                         case USER_TIMECODE_MILLISECONDS:
139                         {
140                                 /* reduced SMPTE. Instead of frames, milliseconds are shown */
141                                 int ms_dp = (power <= 0) ? (1 - power) : 1; /* precision of decimal part */
142                                 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) */
143                                 
144                                 if (hours) sprintf(str, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, cfra);
145                                 else sprintf(str, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, cfra);
146                                 break;
147                         }
148                         case USER_TIMECODE_SECONDS_ONLY:
149                         {
150                                 /* only show the original seconds display */
151                                 /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
152                                 if (power <= 0) sprintf(str, "%.*f", 1 - power, raw_seconds);
153                                 else sprintf(str, "%d", (int)floor(raw_seconds + GLA_PIXEL_OFS));
154                                 break;
155                         }
156                         case USER_TIMECODE_SMPTE_FULL:
157                         default:
158                         {
159                                 /* full SMPTE format */
160                                 sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
161                                 break;
162                         }
163                 }
164         }
165         else {
166                 /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
167                 if (power <= 0) sprintf(str, "%.*f", 1 - power, cfra);
168                 else sprintf(str, "%d", (int)floor(cfra + GLA_PIXEL_OFS));
169         }
170
171
172 /* *************************************************** */
173 /* CURRENT FRAME DRAWING */
174
175 /* Draw current frame number in a little green box beside the current frame indicator */
176 static void draw_cfra_number(Scene *scene, View2D *v2d, float cfra, short time)
177 {
178         float xscale, yscale, x, y;
179         char numstr[32] = "    t";  /* t is the character to start replacing from */
180         short slen;
181         
182         /* because the frame number text is subject to the same scaling as the contents of the view */
183         UI_view2d_getscale(v2d, &xscale, &yscale);
184         glScalef(1.0f / xscale, 1.0f, 1.0f);
185         
186         /* get timecode string 
187          *      - padding on str-buf passed so that it doesn't sit on the frame indicator
188          *      - power = 0, gives 'standard' behavior for time
189          *        but power = 1 is required for frames (to get integer frames)
190          */
191         if (time)
192                 ANIM_timecode_string_from_frame(&numstr[4], scene, 0, time, FRA2TIME(cfra));
193         else
194                 ANIM_timecode_string_from_frame(&numstr[4], scene, 1, time, cfra);
195         slen = (short)UI_GetStringWidth(numstr) - 1;
196         
197         /* get starting coordinates for drawing */
198         x = cfra * xscale;
199         y = 0.9f * U.widget_unit;
200         
201         /* draw green box around/behind text */
202         UI_ThemeColorShade(TH_CFRAME, 0);
203         glRectf(x, y,  x + slen,  y + 0.75f * U.widget_unit);
204         
205         /* draw current frame number - black text */
206         UI_ThemeColor(TH_TEXT);
207         UI_DrawString(x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
208         
209         /* restore view transform */
210         glScalef(xscale, 1.0, 1.0);
211 }
212
213 /* General call for drawing current frame indicator in animation editor */
214 void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
215 {
216         Scene *scene = CTX_data_scene(C);
217         float vec[2];
218         
219         /* Draw a light green line to indicate current frame */
220         vec[0] = (float)(scene->r.cfra * scene->r.framelen);
221         
222         UI_ThemeColor(TH_CFRAME);
223         if (flag & DRAWCFRA_WIDE)
224                 glLineWidth(3.0);
225         else
226                 glLineWidth(2.0);
227         
228         glBegin(GL_LINE_STRIP);
229         vec[1] = v2d->cur.ymin - 500.0f;    /* XXX arbitrary... want it go to bottom */
230         glVertex2fv(vec);
231                 
232         vec[1] = v2d->cur.ymax;
233         glVertex2fv(vec);
234         glEnd();
235         
236         glLineWidth(1.0);
237         
238         /* Draw current frame number in a little box */
239         if (flag & DRAWCFRA_SHOW_NUMBOX) {
240                 UI_view2d_view_orthoSpecial(CTX_wm_region(C), v2d, 1);
241                 draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS));
242         }
243 }
244
245 /* *************************************************** */
246 /* PREVIEW RANGE 'CURTAINS' */
247 /* Note: 'Preview Range' tools are defined in anim_ops.c */
248
249 /* Draw preview range 'curtains' for highlighting where the animation data is */
250 void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
251 {
252         Scene *scene = CTX_data_scene(C);
253         
254         /* only draw this if preview range is set */
255         if (PRVRANGEON) {
256                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
257                 glEnable(GL_BLEND);
258                 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
259                 
260                 /* only draw two separate 'curtains' if there's no overlap between them */
261                 if (PSFRA < PEFRA + end_frame_width) {
262                         glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
263                         glRectf((float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
264                 }
265                 else {
266                         glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
267                 }
268                 
269                 glDisable(GL_BLEND);
270         }
271 }
272
273 /* *************************************************** */
274 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
275
276 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
277 // TODO: do not supply return this if the animdata tells us that there is no mapping to perform
278 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
279 {
280         /* sanity checks */
281         if (ac == NULL)
282                 return NULL;
283         
284         /* abort if rendering - we may get some race condition issues... */
285         if (G.is_rendering) return NULL;
286         
287         /* handling depends on the type of animation-context we've got */
288         if (ale)
289                 return ale->adt;
290         else
291                 return NULL;
292 }
293
294 /* ------------------- */
295
296 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
297 static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
298 {
299         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
300         AnimData *adt = (AnimData *)ked->data;
301         short only_keys = (short)ked->i1;
302         
303         /* adjust BezTriple handles only if allowed to */
304         if (only_keys == 0) {
305                 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
306                 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
307         }
308         
309         bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
310         
311         return 0;
312 }
313
314 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
315 static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
316 {
317         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
318         AnimData *adt = (AnimData *)ked->data;
319         short only_keys = (short)ked->i1;
320         
321         /* adjust BezTriple handles only if allowed to */
322         if (only_keys == 0) {
323                 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
324                 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
325         }
326         
327         bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
328         
329         return 0;
330 }
331
332
333 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve 
334  *      - restore = whether to map points back to non-mapped time 
335  *  - only_keys = whether to only adjust the location of the center point of beztriples
336  */
337 void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, short restore, short only_keys)
338 {
339         KeyframeEditData ked = {{NULL}};
340         KeyframeEditFunc map_cb;
341         
342         /* init edit data 
343          *      - AnimData is stored in 'data'
344          *      - only_keys is stored in 'i1'
345          */
346         ked.data = (void *)adt;
347         ked.i1 = (int)only_keys;
348         
349         /* get editing callback */
350         if (restore)
351                 map_cb = bezt_nlamapping_restore;
352         else
353                 map_cb = bezt_nlamapping_apply;
354         
355         /* apply to F-Curve */
356         ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL);
357 }
358
359 /* *************************************************** */
360 /* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
361
362 /* Get unit conversion factor for given ID + F-Curve */
363 float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short restore)
364 {
365         /* sanity checks */
366         if (id && fcu && fcu->rna_path) {
367                 PointerRNA ptr, id_ptr;
368                 PropertyRNA *prop;
369                 
370                 /* get RNA property that F-Curve affects */
371                 RNA_id_pointer_create(id, &id_ptr);
372                 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
373                         /* rotations: radians <-> degrees? */
374                         if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) {
375                                 /* if the radians flag is not set, default to using degrees which need conversions */
376                                 if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) {
377                                         if (restore)
378                                                 return DEG2RADF(1.0f);  /* degrees to radians */
379                                         else
380                                                 return RAD2DEGF(1.0f);  /* radians to degrees */
381                                 }
382                         }
383                         
384                         /* TODO: other rotation types here as necessary */
385                 }
386         }
387
388         /* no mapping needs to occur... */
389         return 1.0f;
390 }
391
392 /* *************************************************** */