Manual merge of soc-2009-kazanbas branch:
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <string.h>
30 #include <stdio.h>
31 #include <math.h>
32
33 #include "DNA_anim_types.h"
34 #include "DNA_action_types.h"
35 #include "DNA_curve_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_windowmanager_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45
46 #include "BKE_animsys.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_nla.h"
52 #include "BKE_object.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
55
56 #include "ED_anim_api.h"
57 #include "ED_keyframes_edit.h"
58 #include "ED_util.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "BIF_gl.h"
64 #include "BIF_glutil.h"
65
66 #include "UI_interface.h"
67 #include "UI_resources.h"
68 #include "UI_view2d.h"
69
70 /* XXX */
71 extern void ui_rasterpos_safe(float x, float y, float aspect);
72
73 /* *************************************************** */
74 /* CURRENT FRAME DRAWING */
75
76 /* Draw current frame number in a little green box beside the current frame indicator */
77 static void draw_cfra_number (Scene *scene, View2D *v2d, float cfra, short time)
78 {
79         float xscale, yscale, x, y;
80         char str[32];
81         short slen;
82         
83         /* because the frame number text is subject to the same scaling as the contents of the view */
84         UI_view2d_getscale(v2d, &xscale, &yscale);
85         glScalef(1.0f/xscale, 1.0f, 1.0f);
86         
87         if (time) {
88                 /* Timecode:
89                  *      - In general, minutes and seconds should be shown, as most clips will be
90                  *        within this length. Hours will only be included if relevant.
91                  *      - Only show frames when zoomed in enough for them to be relevant 
92                  *        (using separator of '!' for frames).
93                  *        When showing frames, use slightly different display to avoid confusion with mm:ss format
94                  * TODO: factor into reusable function.
95                  * Meanwhile keep in sync:
96                  *        source/blender/editors/animation/anim_draw.c
97                  *        source/blender/editors/interface/view2d.c
98                  */
99                 float val= FRA2TIME(CFRA);
100                 int hours=0, minutes=0, seconds=0, frames=0;
101                 char neg[2]= "";
102                 
103                 /* get values */
104                 if (val < 0) {
105                         /* correction for negative values */
106                         sprintf(neg, "-");
107                         val = -val;
108                 }
109                 if (val >= 3600) {
110                         /* hours */
111                         /* XXX should we only display a single digit for hours since clips are 
112                          *         VERY UNLIKELY to be more than 1-2 hours max? However, that would 
113                          *         go against conventions...
114                          */
115                         hours= (int)val / 3600;
116                         val= (float)fmod(val, 3600);
117                 }
118                 if (val >= 60) {
119                         /* minutes */
120                         minutes= (int)val / 60;
121                         val= (float)fmod(val, 60);
122                 }
123                 {
124                         /* seconds + frames
125                          *      Frames are derived from 'fraction' of second. We need to perform some additional rounding
126                          *      to cope with 'half' frames, etc., which should be fine in most cases
127                          */
128                         seconds= (int)val;
129                         frames= (int)floor( ((val - seconds) * FPS) + 0.5f );
130                 }
131                 
132                 /* print timecode to temp string buffer */
133                 if (hours) sprintf(str, "   %s%02d:%02d:%02d!%02d", neg, hours, minutes, seconds, frames);
134                 else if (minutes) sprintf(str, "   %s%02d:%02d!%02d", neg, minutes, seconds, frames);
135                 else sprintf(str, "   %s%d!%02d", neg, seconds, frames);
136         }
137         else 
138                 sprintf(str, "   %d", CFRA);
139         slen= (short)UI_GetStringWidth(str) - 1;
140         
141         /* get starting coordinates for drawing */
142         x= cfra * xscale;
143         y= 18;
144         
145         /* draw green box around/behind text */
146         UI_ThemeColorShadeAlpha(TH_CFRAME, 0, -100);
147         glRectf(x, y,  x+slen,  y+15);
148         
149         /* draw current frame number - black text */
150         UI_ThemeColor(TH_TEXT);
151         UI_DrawString(x-5, y+3, str); // XXX may need to be updated for font stuff
152         
153         /* restore view transform */
154         glScalef(xscale, 1.0, 1.0);
155 }
156
157 /* General call for drawing current frame indicator in a */
158 void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag)
159 {
160         Scene *scene= CTX_data_scene(C);
161         float vec[2];
162         
163         /* Draw a light green line to indicate current frame */
164         vec[0]= (float)(scene->r.cfra * scene->r.framelen);
165         
166         UI_ThemeColor(TH_CFRAME);
167         glLineWidth(2.0);
168         
169         glBegin(GL_LINE_STRIP);
170                 vec[1]= v2d->cur.ymin-500.0f;   /* XXX arbitrary... want it go to bottom */
171                 glVertex2fv(vec);
172                 
173                 vec[1]= v2d->cur.ymax;
174                 glVertex2fv(vec);
175         glEnd();
176         
177         /* Draw dark green line if slow-parenting/time-offset is enabled */
178         if (flag & DRAWCFRA_SHOW_TIMEOFS) {
179                 Object *ob= (scene->basact) ? (scene->basact->object) : 0;
180                 
181                 // XXX ob->ipoflag is depreceated!
182                 if ((ob) && (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0f)) {
183                         vec[0]-= give_timeoffset(ob); /* could avoid calling twice */
184                         
185                         UI_ThemeColorShade(TH_CFRAME, -30);
186                         
187                         glBegin(GL_LINE_STRIP);
188                                 /*vec[1]= v2d->cur.ymax;*/ // this is set already. this line is only included
189                                 glVertex2fv(vec);
190                                 
191                                 vec[1]= v2d->cur.ymin;
192                                 glVertex2fv(vec);
193                         glEnd();
194                 }
195         }
196         
197         glLineWidth(1.0);
198         
199         /* Draw current frame number in a little box */
200         if (flag & DRAWCFRA_SHOW_NUMBOX) {
201                 UI_view2d_view_orthoSpecial(C, v2d, 1);
202                 draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS));
203         }
204 }
205
206 /* *************************************************** */
207 /* PREVIEW RANGE 'CURTAINS' */
208 /* Note: 'Preview Range' tools are defined in anim_ops.c */
209
210 /* Draw preview range 'curtains' for highlighting where the animation data is */
211 void ANIM_draw_previewrange (const bContext *C, View2D *v2d)
212 {
213         Scene *scene= CTX_data_scene(C);
214         
215         /* only draw this if preview range is set */
216         if (scene->r.psfra) {
217                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
218                 glEnable(GL_BLEND);
219                 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
220                 
221                 /* only draw two separate 'curtains' if there's no overlap between them */
222                 if (PSFRA < PEFRA) {
223                         glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
224                         glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);     
225                 } 
226                 else {
227                         glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
228                 }
229                 
230                 glDisable(GL_BLEND);
231         }
232 }
233
234 /* *************************************************** */
235 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
236
237 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
238 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
239 {
240         /* sanity checks */
241         if (ac == NULL)
242                 return NULL;
243         
244         /* handling depends on the type of animation-context we've got */
245         if (ale)
246                 return ale->adt;
247         else
248                 return NULL;
249 }
250
251 /* ------------------- */
252
253 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
254 static short bezt_nlamapping_restore(BeztEditData *bed, BezTriple *bezt)
255 {
256         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
257         AnimData *adt= (AnimData *)bed->data;
258         short only_keys= (short)bed->i1;
259         
260         /* adjust BezTriple handles only if allowed to */
261         if (only_keys == 0) {
262                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
263                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
264         }
265         
266         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
267         
268         return 0;
269 }
270
271 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
272 static short bezt_nlamapping_apply(BeztEditData *bed, BezTriple *bezt)
273 {
274         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
275         AnimData *adt= (AnimData *)bed->data;
276         short only_keys= (short)bed->i1;
277         
278         /* adjust BezTriple handles only if allowed to */
279         if (only_keys == 0) {
280                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
281                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
282         }
283         
284         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
285         
286         return 0;
287 }
288
289
290
291 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve 
292  *      - restore = whether to map points back to non-mapped time 
293  *      - only_keys = whether to only adjust the location of the center point of beztriples
294  */
295 void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys)
296 {
297         BeztEditData bed;
298         BeztEditFunc map_cb;
299         
300         /* init edit data 
301          *      - AnimData is stored in 'data'
302          *      - only_keys is stored in 'i1'
303          */
304         memset(&bed, 0, sizeof(BeztEditData));
305         bed.data= (void *)adt;
306         bed.i1= (int)only_keys;
307         
308         /* get editing callback */
309         if (restore)
310                 map_cb= bezt_nlamapping_restore;
311         else
312                 map_cb= bezt_nlamapping_apply;
313         
314         /* apply to F-Curve */
315         ANIM_fcurve_keys_bezier_loop(&bed, fcu, NULL, map_cb, NULL);
316
317
318 /* *************************************************** */