|
Blender
V2.59
|
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 /* *************************************************** */