Blender V2.61 - r43446

anim_draw.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Joshua Leung
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00031 #include "BLO_sys_types.h"
00032 
00033 #include "DNA_anim_types.h"
00034 #include "DNA_object_types.h"
00035 #include "DNA_scene_types.h"
00036 #include "BLI_math.h"
00037 
00038 #include "BKE_context.h"
00039 #include "BKE_global.h"
00040 #include "BKE_nla.h"
00041 #include "BKE_object.h"
00042 
00043 #include "ED_anim_api.h"
00044 #include "ED_keyframes_edit.h"
00045 
00046 #include "RNA_access.h"
00047 
00048 #include "BIF_gl.h"
00049 
00050 #include "UI_interface.h"
00051 #include "UI_resources.h"
00052 #include "UI_view2d.h"
00053 
00054 /* XXX */
00055 extern void ui_rasterpos_safe(float x, float y, float aspect);
00056 
00057 /* *************************************************** */
00058 /* TIME CODE FORMATTING */
00059 
00060 /* Generate timecode/frame number string and store in the supplied string 
00061  *  - buffer: must be at least 13 chars long 
00062  *  - power: special setting for View2D grid drawing, 
00063  *    used to specify how detailed we need to be
00064  *  - timecodes: boolean specifying whether timecodes or
00065  *    frame numbers get drawn
00066  *  - cfra: time in frames or seconds, consistent with the values shown by timecodes
00067  */
00068 // TODO: have this in kernel instead under scene?
00069 void ANIM_timecode_string_from_frame (char *str, Scene *scene, int power, short timecodes, float cfra)
00070 {
00071     if (timecodes) {
00072         int hours=0, minutes=0, seconds=0, frames=0;
00073         float raw_seconds= cfra;
00074         char neg[2]= {'\0'};
00075         
00076         /* get cframes */
00077         if (cfra < 0) {
00078             /* correction for negative cfraues */
00079             neg[0]= '-';
00080             cfra = -cfra;
00081         }
00082         if (cfra >= 3600) {
00083             /* hours */
00084             /* XXX should we only display a single digit for hours since clips are 
00085              *     VERY UNLIKELY to be more than 1-2 hours max? However, that would 
00086              *     go against conventions...
00087              */
00088             hours= (int)cfra / 3600;
00089             cfra= (float)fmod(cfra, 3600);
00090         }
00091         if (cfra >= 60) {
00092             /* minutes */
00093             minutes= (int)cfra / 60;
00094             cfra= (float)fmod(cfra, 60);
00095         }
00096         if (power <= 0) {
00097             /* seconds + frames
00098              *  Frames are derived from 'fraction' of second. We need to perform some additional rounding
00099              *  to cope with 'half' frames, etc., which should be fine in most cases
00100              */
00101             seconds= (int)cfra;
00102             frames= (int)floor( (((double)cfra - (double)seconds) * FPS) + 0.5 );
00103         }
00104         else {
00105             /* seconds (with pixel offset rounding) */
00106             seconds= (int)floor(cfra + 0.375f);
00107         }
00108         
00109         switch (U.timecode_style) {
00110             case USER_TIMECODE_MINIMAL: 
00111             {
00112                 /*  - In general, minutes and seconds should be shown, as most clips will be
00113                  *    within this length. Hours will only be included if relevant.
00114                  *  - Only show frames when zoomed in enough for them to be relevant 
00115                  *    (using separator of '+' for frames).
00116                  *    When showing frames, use slightly different display to avoid confusion with mm:ss format
00117                  */
00118                 if (power <= 0) {
00119                     /* include "frames" in display */
00120                     if (hours) sprintf(str, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
00121                     else if (minutes) sprintf(str, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
00122                     else sprintf(str, "%s%d+%02d", neg, seconds, frames);
00123                 }
00124                 else {
00125                     /* don't include 'frames' in display */
00126                     if (hours) sprintf(str, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
00127                     else sprintf(str, "%s%02d:%02d", neg, minutes, seconds);
00128                 }
00129             }
00130                 break;
00131                 
00132             case USER_TIMECODE_SMPTE_MSF:
00133             {
00134                 /* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
00135                 if (hours) sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
00136                 else sprintf(str, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
00137             }
00138                 break;
00139             
00140             case USER_TIMECODE_MILLISECONDS:
00141             {
00142                 /* reduced SMPTE. Instead of frames, milliseconds are shown */
00143                 int ms_dp= (power <= 0) ? (1 - power) : 1; /* precision of decimal part */
00144                 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) */
00145                 
00146                 if (hours) sprintf(str, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, cfra);
00147                 else sprintf(str, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, cfra);
00148             }
00149                 break;
00150                 
00151             case USER_TIMECODE_SECONDS_ONLY:
00152             {
00153                 /* only show the original seconds display */
00154                 /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
00155                 if (power <= 0) sprintf(str, "%.*f", 1-power, raw_seconds);
00156                 else sprintf(str, "%d", (int)floor(raw_seconds + 0.375f));
00157             }
00158                 break;
00159             
00160             case USER_TIMECODE_SMPTE_FULL:
00161             default:
00162             {
00163                 /* full SMPTE format */
00164                 sprintf(str, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
00165             }
00166                 break;
00167         }
00168     }
00169     else {
00170         /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
00171         if (power <= 0) sprintf(str, "%.*f", 1-power, cfra);
00172         else sprintf(str, "%d", (int)floor(cfra + 0.375f));
00173     }
00174 } 
00175 
00176 /* *************************************************** */
00177 /* CURRENT FRAME DRAWING */
00178 
00179 /* Draw current frame number in a little green box beside the current frame indicator */
00180 static void draw_cfra_number (Scene *scene, View2D *v2d, float cfra, short time)
00181 {
00182     float xscale, yscale, x, y;
00183     char numstr[32] = "    t";  /* t is the character to start replacing from */
00184     short slen;
00185     
00186     /* because the frame number text is subject to the same scaling as the contents of the view */
00187     UI_view2d_getscale(v2d, &xscale, &yscale);
00188     glScalef(1.0f/xscale, 1.0f, 1.0f);
00189     
00190     /* get timecode string 
00191      *  - padding on str-buf passed so that it doesn't sit on the frame indicator
00192      *  - power = 0, gives 'standard' behaviour for time
00193      *    but power = 1 is required for frames (to get integer frames)
00194      */
00195     if (time)
00196         ANIM_timecode_string_from_frame(&numstr[4], scene, 0, time, FRA2TIME(cfra));
00197     else    
00198         ANIM_timecode_string_from_frame(&numstr[4], scene, 1, time, cfra);
00199     slen= (short)UI_GetStringWidth(numstr) - 1;
00200     
00201     /* get starting coordinates for drawing */
00202     x= cfra * xscale;
00203     y= 18;
00204     
00205     /* draw green box around/behind text */
00206     UI_ThemeColorShade(TH_CFRAME, 0);
00207     glRectf(x, y,  x+slen,  y+15);
00208     
00209     /* draw current frame number - black text */
00210     UI_ThemeColor(TH_TEXT);
00211     UI_DrawString(x-5, y+3, numstr);
00212     
00213     /* restore view transform */
00214     glScalef(xscale, 1.0, 1.0);
00215 }
00216 
00217 /* General call for drawing current frame indicator in animation editor */
00218 void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag)
00219 {
00220     Scene *scene= CTX_data_scene(C);
00221     float vec[2];
00222     
00223     /* Draw a light green line to indicate current frame */
00224     vec[0]= (float)(scene->r.cfra * scene->r.framelen);
00225     
00226     UI_ThemeColor(TH_CFRAME);
00227     if (flag & DRAWCFRA_WIDE)
00228         glLineWidth(3.0);
00229     else
00230         glLineWidth(2.0);
00231     
00232     glBegin(GL_LINE_STRIP);
00233         vec[1]= v2d->cur.ymin-500.0f;   /* XXX arbitrary... want it go to bottom */
00234         glVertex2fv(vec);
00235         
00236         vec[1]= v2d->cur.ymax;
00237         glVertex2fv(vec);
00238     glEnd();
00239     
00240     glLineWidth(1.0);
00241     
00242     /* Draw current frame number in a little box */
00243     if (flag & DRAWCFRA_SHOW_NUMBOX) {
00244         UI_view2d_view_orthoSpecial(CTX_wm_region(C), v2d, 1);
00245         draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS));
00246     }
00247 }
00248 
00249 /* *************************************************** */
00250 /* PREVIEW RANGE 'CURTAINS' */
00251 /* Note: 'Preview Range' tools are defined in anim_ops.c */
00252 
00253 /* Draw preview range 'curtains' for highlighting where the animation data is */
00254 void ANIM_draw_previewrange (const bContext *C, View2D *v2d)
00255 {
00256     Scene *scene= CTX_data_scene(C);
00257     
00258     /* only draw this if preview range is set */
00259     if (PRVRANGEON) {
00260         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00261         glEnable(GL_BLEND);
00262         glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
00263         
00264         /* only draw two separate 'curtains' if there's no overlap between them */
00265         if (PSFRA < PEFRA) {
00266             glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
00267             glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); 
00268         } 
00269         else {
00270             glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
00271         }
00272         
00273         glDisable(GL_BLEND);
00274     }
00275 }
00276 
00277 /* *************************************************** */
00278 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
00279 
00280 /* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
00281 // TODO: do not supply return this if the animdata tells us that there is no mapping to perform
00282 AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
00283 {
00284     /* sanity checks */
00285     if (ac == NULL)
00286         return NULL;
00287     
00288     /* abort if rendering - we may get some race condition issues... */
00289     if (G.rendering) return NULL;
00290     
00291     /* handling depends on the type of animation-context we've got */
00292     if (ale)
00293         return ale->adt;
00294     else
00295         return NULL;
00296 }
00297 
00298 /* ------------------- */
00299 
00300 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
00301 static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
00302 {
00303     /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
00304     AnimData *adt= (AnimData *)ked->data;
00305     short only_keys= (short)ked->i1;
00306     
00307     /* adjust BezTriple handles only if allowed to */
00308     if (only_keys == 0) {
00309         bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
00310         bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
00311     }
00312     
00313     bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
00314     
00315     return 0;
00316 }
00317 
00318 /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
00319 static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
00320 {
00321     /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
00322     AnimData *adt= (AnimData*)ked->data;
00323     short only_keys= (short)ked->i1;
00324     
00325     /* adjust BezTriple handles only if allowed to */
00326     if (only_keys == 0) {
00327         bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
00328         bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
00329     }
00330     
00331     bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
00332     
00333     return 0;
00334 }
00335 
00336 
00337 /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve 
00338  *  - restore = whether to map points back to non-mapped time 
00339  *  - only_keys = whether to only adjust the location of the center point of beztriples
00340  */
00341 void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys)
00342 {
00343     KeyframeEditData ked= {{NULL}};
00344     KeyframeEditFunc map_cb;
00345     
00346     /* init edit data 
00347      *  - AnimData is stored in 'data'
00348      *  - only_keys is stored in 'i1'
00349      */
00350     ked.data= (void *)adt;
00351     ked.i1= (int)only_keys;
00352     
00353     /* get editing callback */
00354     if (restore)
00355         map_cb= bezt_nlamapping_restore;
00356     else
00357         map_cb= bezt_nlamapping_apply;
00358     
00359     /* apply to F-Curve */
00360     ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL);
00361 }
00362 
00363 /* *************************************************** */
00364 /* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
00365 
00366 /* Get unit conversion factor for given ID + F-Curve */
00367 float ANIM_unit_mapping_get_factor (Scene *scene, ID *id, FCurve *fcu, short restore)
00368 {
00369     /* sanity checks */
00370     if (id && fcu && fcu->rna_path) 
00371     {
00372         PointerRNA ptr, id_ptr;
00373         PropertyRNA *prop;
00374         
00375         /* get RNA property that F-Curve affects */
00376         RNA_id_pointer_create(id, &id_ptr);
00377         if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) 
00378         {
00379             /* rotations: radians <-> degrees? */
00380             if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION)
00381             {
00382                 /* if the radians flag is not set, default to using degrees which need conversions */
00383                 if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) {
00384                     if (restore)
00385                         return DEG2RADF(1.0f);  /* degrees to radians */
00386                     else
00387                         return RAD2DEGF(1.0f);  /* radians to degrees */
00388                 }
00389             }
00390             
00391             // TODO: other rotation types here as necessary
00392         }
00393     }
00394     
00395     /* no mapping needs to occur... */
00396     return 1.0f;
00397 }
00398 
00399 /* ----------------------- */
00400 
00401 /* helper function for ANIM_unit_mapping_apply_fcurve -> mapping callback for unit mapping */
00402 static short bezt_unit_mapping_apply (KeyframeEditData *ked, BezTriple *bezt)
00403 {
00404     /* mapping factor is stored in f1, flags are stored in i1 */
00405     short only_keys= (ked->i1 & ANIM_UNITCONV_ONLYKEYS);
00406     short sel_vs= (ked->i1 & ANIM_UNITCONV_SELVERTS);
00407     float fac= ked->f1;
00408     
00409     /* adjust BezTriple handles only if allowed to */
00410     if (only_keys == 0) {
00411         if ((sel_vs==0) || (bezt->f1 & SELECT)) 
00412             bezt->vec[0][1] *= fac;
00413         if ((sel_vs==0) || (bezt->f3 & SELECT)) 
00414             bezt->vec[2][1] *= fac;
00415     }
00416     
00417     if ((sel_vs == 0) || (bezt->f2 & SELECT))
00418         bezt->vec[1][1] *= fac;
00419     
00420     return 0;
00421 }
00422 
00423 /* Apply/Unapply units conversions to keyframes */
00424 void ANIM_unit_mapping_apply_fcurve (Scene *scene, ID *id, FCurve *fcu, short flag)
00425 {
00426     KeyframeEditData ked;
00427     KeyframeEditFunc sel_cb;
00428     float fac;
00429     
00430     /* abort if rendering - we may get some race condition issues... */
00431     if (G.rendering) return;
00432     
00433     /* calculate mapping factor, and abort if nothing to change */
00434     fac= ANIM_unit_mapping_get_factor(scene, id, fcu, (flag & ANIM_UNITCONV_RESTORE));
00435     if (fac == 1.0f)
00436         return;
00437     
00438     /* init edit data 
00439      *  - mapping factor is stored in f1
00440      *  - flags are stored in 'i1'
00441      */
00442     memset(&ked, 0, sizeof(KeyframeEditData));
00443     ked.f1= (float)fac;
00444     ked.i1= (int)flag;
00445     
00446     /* only selected? */
00447     if (flag & ANIM_UNITCONV_ONLYSEL)
00448         sel_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
00449     else
00450         sel_cb= NULL;
00451     
00452     /* apply to F-Curve */
00453     ANIM_fcurve_keyframes_loop(&ked, fcu, sel_cb, bezt_unit_mapping_apply, NULL);
00454     
00455     // FIXME: loop here for samples should be generalised
00456     // TODO: only sel?
00457     if (fcu->fpt) {
00458         FPoint *fpt;
00459         unsigned int i;
00460         
00461         for (i=0, fpt=fcu->fpt; i < fcu->totvert; i++, fpt++) {
00462             /* apply unit mapping */
00463             fpt->vec[1] *= fac;
00464         }
00465     }
00466 }
00467 
00468 /* *************************************************** */