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