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