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