2dc4aa09407d357760932daf7608dc004dab7c88
[blender-staging.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_main.h"
52 #include "BKE_nla.h"
53 #include "BKE_object.h"
54 #include "BKE_screen.h"
55 #include "BKE_utildefines.h"
56
57 #include "ED_anim_api.h"
58 #include "ED_keyframes_edit.h"
59 #include "ED_types.h"
60 #include "ED_util.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "BIF_gl.h"
66 #include "BIF_glutil.h"
67
68 #include "UI_interface.h"
69 #include "UI_resources.h"
70 #include "UI_view2d.h"
71
72 /* XXX */
73 extern void ui_rasterpos_safe(float x, float y, float aspect);
74
75 /* *************************************************** */
76 /* CURRENT FRAME DRAWING */
77
78 /* Draw current frame number in a little green box beside the current frame indicator */
79 static void draw_cfra_number (Scene *scene, View2D *v2d, float cfra, short time)
80 {
81         float xscale, yscale, x, y;
82         char str[32];
83         short slen;
84         
85         /* because the frame number text is subject to the same scaling as the contents of the view */
86         UI_view2d_getscale(v2d, &xscale, &yscale);
87         glScalef(1.0f/xscale, 1.0f, 1.0f);
88         
89         if (time) {
90                 /* Timecode:
91                  *      - In general, minutes and seconds should be shown, as most clips will be
92                  *        within this length. Hours will only be included if relevant.
93                  *      - Only show frames when zoomed in enough for them to be relevant 
94                  *        (using separator of '!' for frames).
95                  *        When showing frames, use slightly different display to avoid confusion with mm:ss format
96                  * TODO: factor into reusable function.
97                  * Meanwhile keep in sync:
98                  *        source/blender/editors/animation/anim_draw.c
99                  *        source/blender/editors/interface/view2d.c
100                  */
101                 float val= FRA2TIME(CFRA);
102                 int hours=0, minutes=0, seconds=0, frames=0;
103                 char neg[2]= "";
104                 
105                 /* get values */
106                 if (val < 0) {
107                         /* correction for negative values */
108                         sprintf(neg, "-");
109                         val = -val;
110                 }
111                 if (val >= 3600) {
112                         /* hours */
113                         /* XXX should we only display a single digit for hours since clips are 
114                          *         VERY UNLIKELY to be more than 1-2 hours max? However, that would 
115                          *         go against conventions...
116                          */
117                         hours= (int)val / 3600;
118                         val= (float)fmod(val, 3600);
119                 }
120                 if (val >= 60) {
121                         /* minutes */
122                         minutes= (int)val / 60;
123                         val= (float)fmod(val, 60);
124                 }
125                 {
126                         /* seconds + frames
127                          *      Frames are derived from 'fraction' of second. We need to perform some additional rounding
128                          *      to cope with 'half' frames, etc., which should be fine in most cases
129                          */
130                         seconds= (int)val;
131                         frames= (int)floor( ((val - seconds) * FPS) + 0.5f );
132                 }
133                 
134                 /* print timecode to temp string buffer */
135                 if (hours) sprintf(str, "   %s%02d:%02d:%02d!%02d", neg, hours, minutes, seconds, frames);
136                 else if (minutes) sprintf(str, "   %s%02d:%02d!%02d", neg, minutes, seconds, frames);
137                 else sprintf(str, "   %s%d!%02d", neg, seconds, frames);
138         }
139         else 
140                 sprintf(str, "   %d", CFRA);
141         slen= (short)UI_GetStringWidth(str) - 1;
142         
143         /* get starting coordinates for drawing */
144         x= cfra * xscale;
145         y= 18;
146         
147         /* draw green box around/behind text */
148         UI_ThemeColorShadeAlpha(TH_CFRAME, 0, -100);
149         glRectf(x, y,  x+slen,  y+15);
150         
151         /* draw current frame number - black text */
152         UI_ThemeColor(TH_TEXT);
153         UI_DrawString(x-5, y+3, str); // XXX may need to be updated for font stuff
154         
155         /* restore view transform */
156         glScalef(xscale, 1.0, 1.0);
157 }
158
159 /* General call for drawing current frame indicator in a */
160 void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag)
161 {
162         Scene *scene= CTX_data_scene(C);
163         float vec[2];
164         
165         /* Draw a light green line to indicate current frame */
166         vec[0]= (float)(scene->r.cfra * scene->r.framelen);
167         
168         UI_ThemeColor(TH_CFRAME);
169         glLineWidth(2.0);
170         
171         glBegin(GL_LINE_STRIP);
172                 vec[1]= v2d->cur.ymin-500.0f;   /* XXX arbitrary... want it go to bottom */
173                 glVertex2fv(vec);
174                 
175                 vec[1]= v2d->cur.ymax;
176                 glVertex2fv(vec);
177         glEnd();
178         
179         /* Draw dark green line if slow-parenting/time-offset is enabled */
180         if (flag & DRAWCFRA_SHOW_TIMEOFS) {
181                 Object *ob= (scene->basact) ? (scene->basact->object) : 0;
182                 
183                 // XXX ob->ipoflag is depreceated!
184                 if ((ob) && (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0f)) {
185                         vec[0]-= give_timeoffset(ob); /* could avoid calling twice */
186                         
187                         UI_ThemeColorShade(TH_CFRAME, -30);
188                         
189                         glBegin(GL_LINE_STRIP);
190                                 /*vec[1]= v2d->cur.ymax;*/ // this is set already. this line is only included
191                                 glVertex2fv(vec);
192                                 
193                                 vec[1]= v2d->cur.ymin;
194                                 glVertex2fv(vec);
195                         glEnd();
196                 }
197         }
198         
199         glLineWidth(1.0);
200         
201         /* Draw current frame number in a little box */
202         if (flag & DRAWCFRA_SHOW_NUMBOX) {
203                 UI_view2d_view_orthoSpecial(C, v2d, 1);
204                 draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS));
205         }
206 }
207
208 /* *************************************************** */
209 /* PREVIEW RANGE 'CURTAINS' */
210 /* Note: 'Preview Range' tools are defined in anim_ops.c */
211
212 /* Draw preview range 'curtains' for highlighting where the animation data is */
213 void ANIM_draw_previewrange (const bContext *C, View2D *v2d)
214 {
215         Scene *scene= CTX_data_scene(C);
216         
217         /* only draw this if preview range is set */
218         if (scene->r.psfra) {
219                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
220                 glEnable(GL_BLEND);
221                 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
222                 
223                 /* only draw two separate 'curtains' if there's no overlap between them */
224                 if (PSFRA < PEFRA) {
225                         glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
226                         glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);     
227                 } 
228                 else {
229                         glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
230                 }
231                 
232                 glDisable(GL_BLEND);
233         }
234 }
235
236 /* *************************************************** */
237 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
238
239 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
240 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
241 {
242         /* sanity checks */
243         if (ac == NULL)
244                 return NULL;
245         
246         /* handling depends on the type of animation-context we've got */
247         if (ale)
248                 return ale->adt;
249         else
250                 return NULL;
251 }
252
253 /* ------------------- */
254
255 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
256 static short bezt_nlamapping_restore(BeztEditData *bed, BezTriple *bezt)
257 {
258         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
259         AnimData *adt= (AnimData *)bed->data;
260         short only_keys= (short)bed->i1;
261         
262         /* adjust BezTriple handles only if allowed to */
263         if (only_keys == 0) {
264                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
265                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
266         }
267         
268         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
269         
270         return 0;
271 }
272
273 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
274 static short bezt_nlamapping_apply(BeztEditData *bed, BezTriple *bezt)
275 {
276         /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
277         AnimData *adt= (AnimData *)bed->data;
278         short only_keys= (short)bed->i1;
279         
280         /* adjust BezTriple handles only if allowed to */
281         if (only_keys == 0) {
282                 bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
283                 bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
284         }
285         
286         bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
287         
288         return 0;
289 }
290
291
292
293 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve 
294  *      - restore = whether to map points back to non-mapped time 
295  *      - only_keys = whether to only adjust the location of the center point of beztriples
296  */
297 void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys)
298 {
299         BeztEditData bed;
300         BeztEditFunc map_cb;
301         
302         /* init edit data 
303          *      - AnimData is stored in 'data'
304          *      - only_keys is stored in 'i1'
305          */
306         memset(&bed, 0, sizeof(BeztEditData));
307         bed.data= (void *)adt;
308         bed.i1= (int)only_keys;
309         
310         /* get editing callback */
311         if (restore)
312                 map_cb= bezt_nlamapping_restore;
313         else
314                 map_cb= bezt_nlamapping_apply;
315         
316         /* apply to F-Curve */
317         ANIM_fcurve_keys_bezier_loop(&bed, fcu, NULL, map_cb, NULL);
318
319
320 /* *************************************************** */
321 /* ANIMATION EDITOR UI-WIDGETS */
322
323 /* ui button event */
324 #define B_REDR          1
325
326 /* standard header buttons for Animation Editors */
327 short ANIM_headerUI_standard_buttons (const bContext *C, bDopeSheet *ads, uiBlock *block, short xco, short yco)
328 {
329         Main *mainptr= CTX_data_main(C);
330         ScrArea *sa= CTX_wm_area(C);
331         short nlaActive= ((sa) && (sa->spacetype==SPACE_NLA));
332         
333         /* check if the DopeSheet data exists, just in case... */
334         if (ads) {
335                 /* more 'generic' filtering options */
336                 if (nlaActive) uiBlockBeginAlign(block);
337                         uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF,      (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Only display selected Objects");
338                         if (nlaActive) uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data");
339                 if (nlaActive) uiBlockEndAlign(block);
340                 xco += 5;
341                 
342                 /* datatype based - only available datatypes are shown */
343                 uiBlockBeginAlign(block);
344                         uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA,        (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Scene Animation");
345                         uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA,        (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display World Animation");
346                         if (mainptr && mainptr->key.first)
347                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA,       (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys");
348                         if (mainptr && mainptr->mat.first)
349                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA,     (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Material Data");
350                         if (mainptr && mainptr->lamp.first)
351                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Lamp Data");
352                         if (mainptr && mainptr->camera.first)
353                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA,       (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Camera Data");
354                         if (mainptr && mainptr->curve.first)
355                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA,        (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Curve Data");
356                         if (mainptr && mainptr->mball.first)
357                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMBA, B_REDR, ICON_META_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display MetaBall Data");
358                         if (mainptr && mainptr->armature.first)
359                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOARM, B_REDR, ICON_ARMATURE_DATA,     (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Armature Data");
360                         if (mainptr && mainptr->particle.first)
361                                 uiDefIconButBitI(block, TOGN, ADS_FILTER_NOPART, B_REDR, ICON_PARTICLE_DATA,    (short)(xco+=XIC),yco,XIC,YIC, &(ads->filterflag), 0, 0, 0, 0, "Display Particle Data");
362                 uiBlockEndAlign(block);
363                 xco += 30;
364         }
365         else {
366                 // XXX this case shouldn't happen at all... for now, just pad out same amount of space
367                 printf("ERROR: dopesheet data not available when drawing Animation Editor header \n");
368                 xco += 11*XIC + 30;
369         }
370         
371         // TODO: include auto-snapping menu here too...
372         
373         /* return the width of the buttons */
374         return xco;
375 }
376
377 /* *************************************************** */