|
Blender
V2.59
|
00001 /* 00002 * $Id: nla.c 35836 2011-03-28 04:22:50Z 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) 2009 Blender Foundation, Joshua Leung 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): Joshua Leung (full recode) 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <stdlib.h> 00036 #include <stddef.h> 00037 #include <stdio.h> 00038 #include <string.h> 00039 #include <math.h> 00040 #include <float.h> 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BLI_utildefines.h" 00045 #include "BLI_ghash.h" 00046 00047 #include "DNA_anim_types.h" 00048 #include "DNA_scene_types.h" 00049 00050 #include "BKE_action.h" 00051 #include "BKE_fcurve.h" 00052 #include "BKE_nla.h" 00053 #include "BKE_global.h" 00054 #include "BKE_library.h" 00055 00056 00057 #include "RNA_access.h" 00058 #include "nla_private.h" 00059 00060 00061 00062 /* *************************************************** */ 00063 /* Data Management */ 00064 00065 /* Freeing ------------------------------------------- */ 00066 00067 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data, 00068 * and the strip itself. 00069 */ 00070 void free_nlastrip (ListBase *strips, NlaStrip *strip) 00071 { 00072 NlaStrip *cs, *csn; 00073 00074 /* sanity checks */ 00075 if (strip == NULL) 00076 return; 00077 00078 /* free child-strips */ 00079 for (cs= strip->strips.first; cs; cs= csn) { 00080 csn= cs->next; 00081 free_nlastrip(&strip->strips, cs); 00082 } 00083 00084 /* remove reference to action */ 00085 if (strip->act) 00086 id_us_min(&strip->act->id); 00087 00088 /* free remapping info */ 00089 //if (strip->remap) 00090 // BKE_animremap_free(); 00091 00092 /* free own F-Curves */ 00093 free_fcurves(&strip->fcurves); 00094 00095 /* free own F-Modifiers */ 00096 free_fmodifiers(&strip->modifiers); 00097 00098 /* free the strip itself */ 00099 if (strips) 00100 BLI_freelinkN(strips, strip); 00101 else 00102 MEM_freeN(strip); 00103 } 00104 00105 /* Remove the given NLA track from the set of NLA tracks, free the track's data, 00106 * and the track itself. 00107 */ 00108 void free_nlatrack (ListBase *tracks, NlaTrack *nlt) 00109 { 00110 NlaStrip *strip, *stripn; 00111 00112 /* sanity checks */ 00113 if (nlt == NULL) 00114 return; 00115 00116 /* free strips */ 00117 for (strip= nlt->strips.first; strip; strip= stripn) { 00118 stripn= strip->next; 00119 free_nlastrip(&nlt->strips, strip); 00120 } 00121 00122 /* free NLA track itself now */ 00123 if (tracks) 00124 BLI_freelinkN(tracks, nlt); 00125 else 00126 MEM_freeN(nlt); 00127 } 00128 00129 /* Free the elements of type NLA Tracks provided in the given list, but do not free 00130 * the list itself since that is not free-standing 00131 */ 00132 void free_nladata (ListBase *tracks) 00133 { 00134 NlaTrack *nlt, *nltn; 00135 00136 /* sanity checks */ 00137 if ELEM(NULL, tracks, tracks->first) 00138 return; 00139 00140 /* free tracks one by one */ 00141 for (nlt= tracks->first; nlt; nlt= nltn) { 00142 nltn= nlt->next; 00143 free_nlatrack(tracks, nlt); 00144 } 00145 00146 /* clear the list's pointers to be safe */ 00147 tracks->first= tracks->last= NULL; 00148 } 00149 00150 /* Copying ------------------------------------------- */ 00151 00152 /* Copy NLA strip */ 00153 NlaStrip *copy_nlastrip (NlaStrip *strip) 00154 { 00155 NlaStrip *strip_d; 00156 NlaStrip *cs, *cs_d; 00157 00158 /* sanity check */ 00159 if (strip == NULL) 00160 return NULL; 00161 00162 /* make a copy */ 00163 strip_d= MEM_dupallocN(strip); 00164 strip_d->next= strip_d->prev= NULL; 00165 00166 /* increase user-count of action */ 00167 if (strip_d->act) 00168 id_us_plus(&strip_d->act->id); 00169 00170 /* copy F-Curves and modifiers */ 00171 copy_fcurves(&strip_d->fcurves, &strip->fcurves); 00172 copy_fmodifiers(&strip_d->modifiers, &strip->modifiers); 00173 00174 /* make a copy of all the child-strips, one at a time */ 00175 strip_d->strips.first= strip_d->strips.last= NULL; 00176 00177 for (cs= strip->strips.first; cs; cs= cs->next) { 00178 cs_d= copy_nlastrip(cs); 00179 BLI_addtail(&strip_d->strips, cs_d); 00180 } 00181 00182 /* return the strip */ 00183 return strip_d; 00184 } 00185 00186 /* Copy NLA Track */ 00187 NlaTrack *copy_nlatrack (NlaTrack *nlt) 00188 { 00189 NlaStrip *strip, *strip_d; 00190 NlaTrack *nlt_d; 00191 00192 /* sanity check */ 00193 if (nlt == NULL) 00194 return NULL; 00195 00196 /* make a copy */ 00197 nlt_d= MEM_dupallocN(nlt); 00198 nlt_d->next= nlt_d->prev= NULL; 00199 00200 /* make a copy of all the strips, one at a time */ 00201 nlt_d->strips.first= nlt_d->strips.last= NULL; 00202 00203 for (strip= nlt->strips.first; strip; strip= strip->next) { 00204 strip_d= copy_nlastrip(strip); 00205 BLI_addtail(&nlt_d->strips, strip_d); 00206 } 00207 00208 /* return the copy */ 00209 return nlt_d; 00210 } 00211 00212 /* Copy all NLA data */ 00213 void copy_nladata (ListBase *dst, ListBase *src) 00214 { 00215 NlaTrack *nlt, *nlt_d; 00216 00217 /* sanity checks */ 00218 if ELEM(NULL, dst, src) 00219 return; 00220 00221 /* clear out the destination list first for precautions... */ 00222 dst->first= dst->last= NULL; 00223 00224 /* copy each NLA-track, one at a time */ 00225 for (nlt= src->first; nlt; nlt= nlt->next) { 00226 /* make a copy, and add the copy to the destination list */ 00227 nlt_d= copy_nlatrack(nlt); 00228 BLI_addtail(dst, nlt_d); 00229 } 00230 } 00231 00232 /* Adding ------------------------------------------- */ 00233 00234 /* Add a NLA Track to the given AnimData 00235 * - prev: NLA-Track to add the new one after 00236 */ 00237 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev) 00238 { 00239 NlaTrack *nlt; 00240 00241 /* sanity checks */ 00242 if (adt == NULL) 00243 return NULL; 00244 00245 /* allocate new track */ 00246 nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack"); 00247 00248 /* set settings requiring the track to not be part of the stack yet */ 00249 nlt->flag = NLATRACK_SELECTED; 00250 nlt->index= BLI_countlist(&adt->nla_tracks); 00251 00252 /* add track to stack, and make it the active one */ 00253 if (prev) 00254 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt); 00255 else 00256 BLI_addtail(&adt->nla_tracks, nlt); 00257 BKE_nlatrack_set_active(&adt->nla_tracks, nlt); 00258 00259 /* must have unique name, but we need to seed this */ 00260 strcpy(nlt->name, "NlaTrack"); 00261 BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), sizeof(nlt->name)); 00262 00263 /* return the new track */ 00264 return nlt; 00265 } 00266 00267 /* Add a NLA Strip referencing the given Action */ 00268 NlaStrip *add_nlastrip (bAction *act) 00269 { 00270 NlaStrip *strip; 00271 00272 /* sanity checks */ 00273 if (act == NULL) 00274 return NULL; 00275 00276 /* allocate new strip */ 00277 strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip"); 00278 00279 /* generic settings 00280 * - selected flag to highlight this to the user 00281 * - auto-blends to ensure that blend in/out values are automatically 00282 * determined by overlaps of strips 00283 * - (XXX) synchronisation of strip-length in accordance with changes to action-length 00284 * is not done though, since this should only really happens in editmode for strips now 00285 * though this decision is still subject to further review... 00286 */ 00287 strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS; 00288 00289 /* assign the action reference */ 00290 strip->act= act; 00291 id_us_plus(&act->id); 00292 00293 /* determine initial range 00294 * - strip length cannot be 0... ever... 00295 */ 00296 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); 00297 00298 strip->start = strip->actstart; 00299 strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f): (strip->actend); 00300 00301 /* strip should be referenced as-is */ 00302 strip->scale= 1.0f; 00303 strip->repeat = 1.0f; 00304 00305 /* return the new strip */ 00306 return strip; 00307 } 00308 00309 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */ 00310 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act) 00311 { 00312 NlaStrip *strip; 00313 NlaTrack *nlt; 00314 00315 /* sanity checks */ 00316 if ELEM(NULL, adt, act) 00317 return NULL; 00318 00319 /* create a new NLA strip */ 00320 strip= add_nlastrip(act); 00321 if (strip == NULL) 00322 return NULL; 00323 00324 /* firstly try adding strip to last track, but if that fails, add to a new track */ 00325 if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) { 00326 /* trying to add to the last track failed (no track or no space), 00327 * so add a new track to the stack, and add to that... 00328 */ 00329 nlt= add_nlatrack(adt, NULL); 00330 BKE_nlatrack_add_strip(nlt, strip); 00331 } 00332 00333 /* automatically name it too */ 00334 BKE_nlastrip_validate_name(adt, strip); 00335 00336 /* returns the strip added */ 00337 return strip; 00338 } 00339 00340 /* *************************************************** */ 00341 /* NLA Evaluation <-> Editing Stuff */ 00342 00343 /* Strip Mapping ------------------------------------- */ 00344 00345 /* non clipped mapping for strip-time <-> global time (for Action-Clips) 00346 * invert = convert action-strip time to global time 00347 */ 00348 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode) 00349 { 00350 float actlength, scale; 00351 // float repeat; // UNUSED 00352 00353 /* get number of repeats */ 00354 if (IS_EQF(strip->repeat, 0.0f)) strip->repeat = 1.0f; 00355 // repeat = strip->repeat; // UNUSED 00356 00357 /* scaling */ 00358 if (IS_EQF(strip->scale, 0.0f)) strip->scale= 1.0f; 00359 scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */ 00360 00361 /* length of referenced action */ 00362 actlength = strip->actend - strip->actstart; 00363 if (IS_EQF(actlength, 0.0f)) actlength = 1.0f; 00364 00365 /* reversed = play strip backwards */ 00366 if (strip->flag & NLASTRIP_FLAG_REVERSE) { 00367 // FIXME: this won't work right with Graph Editor? 00368 if (mode == NLATIME_CONVERT_MAP) { 00369 return strip->end - scale*(cframe - strip->actstart); 00370 } 00371 else if (mode == NLATIME_CONVERT_UNMAP) { 00372 return (strip->end + (strip->actstart * scale - cframe)) / scale; 00373 } 00374 else /* if (mode == NLATIME_CONVERT_EVAL) */{ 00375 if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { 00376 /* this case prevents the motion snapping back to the first frame at the end of the strip 00377 * by catching the case where repeats is a whole number, which means that the end of the strip 00378 * could also be interpreted as the end of the start of a repeat 00379 */ 00380 return strip->actstart; 00381 } 00382 else { 00383 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working 00384 * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat 00385 */ 00386 return strip->actend - fmodf(cframe - strip->start, actlength*scale) / scale; 00387 } 00388 } 00389 } 00390 else { 00391 if (mode == NLATIME_CONVERT_MAP) { 00392 return strip->start + scale*(cframe - strip->actstart); 00393 } 00394 else if (mode == NLATIME_CONVERT_UNMAP) { 00395 return strip->actstart + (cframe - strip->start) / scale; 00396 } 00397 else /* if (mode == NLATIME_CONVERT_EVAL) */{ 00398 if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { 00399 /* this case prevents the motion snapping back to the first frame at the end of the strip 00400 * by catching the case where repeats is a whole number, which means that the end of the strip 00401 * could also be interpreted as the end of the start of a repeat 00402 */ 00403 return strip->actend; 00404 } 00405 else { 00406 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working 00407 * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat 00408 */ 00409 return strip->actstart + fmodf(cframe - strip->start, actlength*scale) / scale; 00410 } 00411 } 00412 } 00413 } 00414 00415 /* non clipped mapping for strip-time <-> global time (for Transitions) 00416 * invert = convert action-strip time to global time 00417 */ 00418 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode) 00419 { 00420 float length; 00421 00422 /* length of strip */ 00423 length= strip->end - strip->start; 00424 00425 /* reversed = play strip backwards */ 00426 if (strip->flag & NLASTRIP_FLAG_REVERSE) { 00427 if (mode == NLATIME_CONVERT_MAP) 00428 return strip->end - (length * cframe); 00429 else 00430 return (strip->end - cframe) / length; 00431 } 00432 else { 00433 if (mode == NLATIME_CONVERT_MAP) 00434 return (length * cframe) + strip->start; 00435 else 00436 return (cframe - strip->start) / length; 00437 } 00438 } 00439 00440 /* non clipped mapping for strip-time <-> global time 00441 * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_* 00442 * 00443 * only secure for 'internal' (i.e. within AnimSys evaluation) operations, 00444 * but should not be directly relied on for stuff which interacts with editors 00445 */ 00446 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode) 00447 { 00448 switch (strip->type) { 00449 case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */ 00450 case NLASTRIP_TYPE_TRANSITION: /* transition */ 00451 return nlastrip_get_frame_transition(strip, cframe, mode); 00452 00453 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */ 00454 default: 00455 return nlastrip_get_frame_actionclip(strip, cframe, mode); 00456 } 00457 } 00458 00459 00460 /* Non clipped mapping for strip-time <-> global time 00461 * mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_* 00462 * 00463 * Public API method - perform this mapping using the given AnimData block 00464 * and perform any necessary sanity checks on the value 00465 */ 00466 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode) 00467 { 00468 NlaStrip *strip; 00469 00470 /* sanity checks 00471 * - obviously we've got to have some starting data 00472 * - when not in tweakmode, the active Action does not have any scaling applied :) 00473 * - when in tweakmode, if the no-mapping flag is set, do not map 00474 */ 00475 if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP)) 00476 return cframe; 00477 00478 /* if the active-strip info has been stored already, access this, otherwise look this up 00479 * and store for (very probable) future usage 00480 */ 00481 if (adt->actstrip == NULL) { 00482 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks); 00483 adt->actstrip= BKE_nlastrip_find_active(nlt); 00484 } 00485 strip= adt->actstrip; 00486 00487 /* sanity checks 00488 * - in rare cases, we may not be able to find this strip for some reason (internal error) 00489 * - for now, if the user has defined a curve to control the time, this correction cannot be performed 00490 * reliably... 00491 */ 00492 if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME)) 00493 return cframe; 00494 00495 /* perform the correction now... */ 00496 return nlastrip_get_frame(strip, cframe, mode); 00497 } 00498 00499 /* *************************************************** */ 00500 /* NLA API */ 00501 00502 /* List of Strips ------------------------------------ */ 00503 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */ 00504 00505 /* Check if there is any space in the given list to add the given strip */ 00506 short BKE_nlastrips_has_space (ListBase *strips, float start, float end) 00507 { 00508 NlaStrip *strip; 00509 00510 /* sanity checks */ 00511 if ((strips == NULL) || IS_EQF(start, end)) 00512 return 0; 00513 if (start > end) { 00514 puts("BKE_nlastrips_has_space() error... start and end arguments swapped"); 00515 SWAP(float, start, end); 00516 } 00517 00518 /* loop over NLA strips checking for any overlaps with this area... */ 00519 for (strip= strips->first; strip; strip= strip->next) { 00520 /* if start frame of strip is past the target end-frame, that means that 00521 * we've gone past the window we need to check for, so things are fine 00522 */ 00523 if (strip->start >= end) 00524 return 1; 00525 00526 /* if the end of the strip is greater than either of the boundaries, the range 00527 * must fall within the extents of the strip 00528 */ 00529 if ((strip->end > start) || (strip->end > end)) 00530 return 0; 00531 } 00532 00533 /* if we are still here, we haven't encountered any overlapping strips */ 00534 return 1; 00535 } 00536 00537 /* Rearrange the strips in the track so that they are always in order 00538 * (usually only needed after a strip has been moved) 00539 */ 00540 void BKE_nlastrips_sort_strips (ListBase *strips) 00541 { 00542 ListBase tmp = {NULL, NULL}; 00543 NlaStrip *strip, *sstrip, *stripn; 00544 00545 /* sanity checks */ 00546 if ELEM(NULL, strips, strips->first) 00547 return; 00548 00549 /* we simply perform insertion sort on this list, since it is assumed that per track, 00550 * there are only likely to be at most 5-10 strips 00551 */ 00552 for (strip= strips->first; strip; strip= stripn) { 00553 short not_added = 1; 00554 00555 stripn= strip->next; 00556 00557 /* remove this strip from the list, and add it to the new list, searching from the end of 00558 * the list, assuming that the lists are in order 00559 */ 00560 BLI_remlink(strips, strip); 00561 00562 for (sstrip= tmp.last; sstrip; sstrip= sstrip->prev) { 00563 /* check if add after */ 00564 if (sstrip->end <= strip->start) { 00565 BLI_insertlinkafter(&tmp, sstrip, strip); 00566 not_added= 0; 00567 break; 00568 } 00569 } 00570 00571 /* add before first? */ 00572 if (not_added) 00573 BLI_addhead(&tmp, strip); 00574 } 00575 00576 /* reassign the start and end points of the strips */ 00577 strips->first= tmp.first; 00578 strips->last= tmp.last; 00579 } 00580 00581 /* Add the given NLA-Strip to the given list of strips, assuming that it 00582 * isn't currently a member of another list 00583 */ 00584 short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip) 00585 { 00586 NlaStrip *ns; 00587 short not_added = 1; 00588 00589 /* sanity checks */ 00590 if ELEM(NULL, strips, strip) 00591 return 0; 00592 00593 /* check if any space to add */ 00594 if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0) 00595 return 0; 00596 00597 /* find the right place to add the strip to the nominated track */ 00598 for (ns= strips->first; ns; ns= ns->next) { 00599 /* if current strip occurs after the new strip, add it before */ 00600 if (ns->start >= strip->end) { 00601 BLI_insertlinkbefore(strips, ns, strip); 00602 not_added= 0; 00603 break; 00604 } 00605 } 00606 if (not_added) { 00607 /* just add to the end of the list of the strips then... */ 00608 BLI_addtail(strips, strip); 00609 } 00610 00611 /* added... */ 00612 return 1; 00613 } 00614 00615 00616 /* Meta-Strips ------------------------------------ */ 00617 00618 /* Convert 'islands' (i.e. continuous string of) selected strips to be 00619 * contained within 'Meta-Strips' which act as strips which contain strips. 00620 * temp: are the meta-strips to be created 'temporary' ones used for transforms? 00621 */ 00622 void BKE_nlastrips_make_metas (ListBase *strips, short temp) 00623 { 00624 NlaStrip *mstrip = NULL; 00625 NlaStrip *strip, *stripn; 00626 00627 /* sanity checks */ 00628 if ELEM(NULL, strips, strips->first) 00629 return; 00630 00631 /* group all continuous chains of selected strips into meta-strips */ 00632 for (strip= strips->first; strip; strip= stripn) { 00633 stripn= strip->next; 00634 00635 if (strip->flag & NLASTRIP_FLAG_SELECT) { 00636 /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */ 00637 if (mstrip == NULL) { 00638 /* add a new meta-strip, and add it before the current strip that it will replace... */ 00639 mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip"); 00640 mstrip->type = NLASTRIP_TYPE_META; 00641 BLI_insertlinkbefore(strips, strip, mstrip); 00642 00643 /* set flags */ 00644 mstrip->flag = NLASTRIP_FLAG_SELECT; 00645 00646 /* set temp flag if appropriate (i.e. for transform-type editing) */ 00647 if (temp) 00648 mstrip->flag |= NLASTRIP_FLAG_TEMP_META; 00649 00650 /* set default repeat/scale values to prevent warnings */ 00651 mstrip->repeat= mstrip->scale= 1.0f; 00652 00653 /* make its start frame be set to the start frame of the current strip */ 00654 mstrip->start= strip->start; 00655 } 00656 00657 /* remove the selected strips from the track, and add to the meta */ 00658 BLI_remlink(strips, strip); 00659 BLI_addtail(&mstrip->strips, strip); 00660 00661 /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */ 00662 mstrip->end= strip->end; 00663 } 00664 else { 00665 /* current strip wasn't selected, so the end of 'island' of selected strips has been reached, 00666 * so stop adding strips to the current meta 00667 */ 00668 mstrip= NULL; 00669 } 00670 } 00671 } 00672 00673 /* Split a meta-strip into a set of normal strips */ 00674 void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip) 00675 { 00676 NlaStrip *cs, *csn; 00677 00678 /* sanity check */ 00679 if ELEM(NULL, strips, strip) 00680 return; 00681 00682 /* move each one of the meta-strip's children before the meta-strip 00683 * in the list of strips after unlinking them from the meta-strip 00684 */ 00685 for (cs= strip->strips.first; cs; cs= csn) { 00686 csn= cs->next; 00687 BLI_remlink(&strip->strips, cs); 00688 BLI_insertlinkbefore(strips, strip, cs); 00689 } 00690 00691 /* free the meta-strip now */ 00692 free_nlastrip(strips, strip); 00693 } 00694 00695 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips 00696 * sel: only consider selected meta-strips, otherwise all meta-strips are removed 00697 * onlyTemp: only remove the 'temporary' meta-strips used for transforms 00698 */ 00699 void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp) 00700 { 00701 NlaStrip *strip, *stripn; 00702 00703 /* sanity checks */ 00704 if ELEM(NULL, strips, strips->first) 00705 return; 00706 00707 /* remove meta-strips fitting the criteria of the arguments */ 00708 for (strip= strips->first; strip; strip= stripn) { 00709 stripn= strip->next; 00710 00711 /* check if strip is a meta-strip */ 00712 if (strip->type == NLASTRIP_TYPE_META) { 00713 /* if check if selection and 'temporary-only' considerations are met */ 00714 if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) { 00715 if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) { 00716 BKE_nlastrips_clear_metastrip(strips, strip); 00717 } 00718 } 00719 } 00720 } 00721 } 00722 00723 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the 00724 * strip isn't attached to anyy list of strips 00725 */ 00726 short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip) 00727 { 00728 /* sanity checks */ 00729 if ELEM(NULL, mstrip, strip) 00730 return 0; 00731 00732 /* firstly, check if the meta-strip has space for this */ 00733 if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0) 00734 return 0; 00735 00736 /* check if this would need to be added to the ends of the meta, 00737 * and subsequently, if the neighbouring strips allow us enough room 00738 */ 00739 if (strip->start < mstrip->start) { 00740 /* check if strip to the left (if it exists) ends before the 00741 * start of the strip we're trying to add 00742 */ 00743 if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) { 00744 /* add strip to start of meta's list, and expand dimensions */ 00745 BLI_addhead(&mstrip->strips, strip); 00746 mstrip->start= strip->start; 00747 00748 return 1; 00749 } 00750 else /* failed... no room before */ 00751 return 0; 00752 } 00753 else if (strip->end > mstrip->end) { 00754 /* check if strip to the right (if it exists) starts before the 00755 * end of the strip we're trying to add 00756 */ 00757 if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) { 00758 /* add strip to end of meta's list, and expand dimensions */ 00759 BLI_addtail(&mstrip->strips, strip); 00760 mstrip->end= strip->end; 00761 00762 return 1; 00763 } 00764 else /* failed... no room after */ 00765 return 0; 00766 } 00767 else { 00768 /* just try to add to the meta-strip (no dimension changes needed) */ 00769 return BKE_nlastrips_add_strip(&mstrip->strips, strip); 00770 } 00771 } 00772 00773 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively), 00774 * until the Meta-Strips children all fit within the Meta-Strip's new dimensions 00775 */ 00776 void BKE_nlameta_flush_transforms (NlaStrip *mstrip) 00777 { 00778 NlaStrip *strip; 00779 float oStart, oEnd, offset; 00780 float oLen, nLen; 00781 short scaleChanged= 0; 00782 00783 /* sanity checks 00784 * - strip must exist 00785 * - strip must be a meta-strip with some contents 00786 */ 00787 if ELEM(NULL, mstrip, mstrip->strips.first) 00788 return; 00789 if (mstrip->type != NLASTRIP_TYPE_META) 00790 return; 00791 00792 /* get the original start/end points, and calculate the start-frame offset 00793 * - these are simply the start/end frames of the child strips, 00794 * since we assume they weren't transformed yet 00795 */ 00796 oStart= ((NlaStrip *)mstrip->strips.first)->start; 00797 oEnd= ((NlaStrip *)mstrip->strips.last)->end; 00798 offset= mstrip->start - oStart; 00799 00800 /* optimisation: 00801 * don't flush if nothing changed yet 00802 * TODO: maybe we need a flag to say always flush? 00803 */ 00804 if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end)) 00805 return; 00806 00807 /* check if scale changed */ 00808 oLen = oEnd - oStart; 00809 nLen = mstrip->end - mstrip->start; 00810 if (IS_EQF(nLen, oLen) == 0) 00811 scaleChanged= 1; 00812 00813 /* for each child-strip, calculate new start/end points based on this new info */ 00814 for (strip= mstrip->strips.first; strip; strip= strip->next) { 00815 if (scaleChanged) { 00816 PointerRNA ptr; 00817 float p1, p2, nStart, nEnd; 00818 00819 /* compute positions of endpoints relative to old extents of strip */ 00820 p1= (strip->start - oStart) / oLen; 00821 p2= (strip->end - oStart) / oLen; 00822 00823 /* compute the new strip endpoints using the proportions */ 00824 nStart= (p1 * nLen) + mstrip->start; 00825 nEnd= (p2 * nLen) + mstrip->start; 00826 00827 /* firstly, apply the new positions manually, then apply using RNA 00828 * - first time is to make sure no truncation errors from one endpoint not being 00829 * set yet occur 00830 * - second time is to make sure scale is computed properly... 00831 */ 00832 strip->start= nStart; 00833 strip->end= nEnd; 00834 00835 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr); 00836 RNA_float_set(&ptr, "frame_start", nStart); 00837 RNA_float_set(&ptr, "frame_end", nEnd); 00838 } 00839 else { 00840 /* just apply the changes in offset to both ends of the strip */ 00841 strip->start += offset; 00842 strip->end += offset; 00843 } 00844 00845 /* finally, make sure the strip's children (if it is a meta-itself), get updated */ 00846 BKE_nlameta_flush_transforms(strip); 00847 } 00848 } 00849 00850 /* NLA-Tracks ---------------------------------------- */ 00851 00852 /* Find the active NLA-track for the given stack */ 00853 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks) 00854 { 00855 NlaTrack *nlt; 00856 00857 /* sanity check */ 00858 if ELEM(NULL, tracks, tracks->first) 00859 return NULL; 00860 00861 /* try to find the first active track */ 00862 for (nlt= tracks->first; nlt; nlt= nlt->next) { 00863 if (nlt->flag & NLATRACK_ACTIVE) 00864 return nlt; 00865 } 00866 00867 /* none found */ 00868 return NULL; 00869 } 00870 00871 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one 00872 * that has this status in its AnimData block. 00873 */ 00874 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt) 00875 { 00876 NlaTrack *nt; 00877 00878 /* sanity check */ 00879 if ELEM(NULL, adt, adt->nla_tracks.first) 00880 return; 00881 00882 /* firstly, make sure 'solo' flag for all tracks is disabled */ 00883 for (nt= adt->nla_tracks.first; nt; nt= nt->next) { 00884 if (nt != nlt) 00885 nt->flag &= ~NLATRACK_SOLO; 00886 } 00887 00888 /* now, enable 'solo' for the given track if appropriate */ 00889 if (nlt) { 00890 /* toggle solo status */ 00891 nlt->flag ^= NLATRACK_SOLO; 00892 00893 /* set or clear solo-status on AnimData */ 00894 if (nlt->flag & NLATRACK_SOLO) 00895 adt->flag |= ADT_NLA_SOLO_TRACK; 00896 else 00897 adt->flag &= ~ADT_NLA_SOLO_TRACK; 00898 } 00899 else 00900 adt->flag &= ~ADT_NLA_SOLO_TRACK; 00901 } 00902 00903 /* Make the given NLA-track the active one for the given stack. If no track is provided, 00904 * this function can be used to simply deactivate all the NLA tracks in the given stack too. 00905 */ 00906 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a) 00907 { 00908 NlaTrack *nlt; 00909 00910 /* sanity check */ 00911 if ELEM(NULL, tracks, tracks->first) 00912 return; 00913 00914 /* deactive all the rest */ 00915 for (nlt= tracks->first; nlt; nlt= nlt->next) 00916 nlt->flag &= ~NLATRACK_ACTIVE; 00917 00918 /* set the given one as the active one */ 00919 if (nlt_a) 00920 nlt_a->flag |= NLATRACK_ACTIVE; 00921 } 00922 00923 /* Check if there is any space in the given track to add a strip of the given length */ 00924 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end) 00925 { 00926 /* sanity checks 00927 * - track must exist 00928 * - track must be editable 00929 * - bounds cannot be equal (0-length is nasty) 00930 */ 00931 if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end)) 00932 return 0; 00933 00934 if (start > end) { 00935 puts("BKE_nlatrack_has_space() error... start and end arguments swapped"); 00936 SWAP(float, start, end); 00937 } 00938 00939 /* check if there's any space left in the track for a strip of the given length */ 00940 return BKE_nlastrips_has_space(&nlt->strips, start, end); 00941 } 00942 00943 /* Rearrange the strips in the track so that they are always in order 00944 * (usually only needed after a strip has been moved) 00945 */ 00946 void BKE_nlatrack_sort_strips (NlaTrack *nlt) 00947 { 00948 /* sanity checks */ 00949 if ELEM(NULL, nlt, nlt->strips.first) 00950 return; 00951 00952 /* sort the strips with a more generic function */ 00953 BKE_nlastrips_sort_strips(&nlt->strips); 00954 } 00955 00956 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 00957 * isn't currently attached to another one 00958 */ 00959 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip) 00960 { 00961 /* sanity checks */ 00962 if ELEM(NULL, nlt, strip) 00963 return 0; 00964 00965 /* try to add the strip to the track using a more generic function */ 00966 return BKE_nlastrips_add_strip(&nlt->strips, strip); 00967 } 00968 00969 /* Get the extents of the given NLA-Track including gaps between strips, 00970 * returning whether this succeeded or not 00971 */ 00972 short BKE_nlatrack_get_bounds (NlaTrack *nlt, float bounds[2]) 00973 { 00974 NlaStrip *strip; 00975 00976 /* initialise bounds */ 00977 if (bounds) 00978 bounds[0] = bounds[1] = 0.0f; 00979 else 00980 return 0; 00981 00982 /* sanity checks */ 00983 if ELEM(NULL, nlt, nlt->strips.first) 00984 return 0; 00985 00986 /* lower bound is first strip's start frame */ 00987 strip = nlt->strips.first; 00988 bounds[0] = strip->start; 00989 00990 /* upper bound is last strip's end frame */ 00991 strip = nlt->strips.last; 00992 bounds[1] = strip->end; 00993 00994 /* done */ 00995 return 1; 00996 } 00997 00998 /* NLA Strips -------------------------------------- */ 00999 01000 /* Find the active NLA-strip within the given track */ 01001 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt) 01002 { 01003 NlaStrip *strip; 01004 01005 /* sanity check */ 01006 if ELEM(NULL, nlt, nlt->strips.first) 01007 return NULL; 01008 01009 /* try to find the first active strip */ 01010 for (strip= nlt->strips.first; strip; strip= strip->next) { 01011 if (strip->flag & NLASTRIP_FLAG_ACTIVE) 01012 return strip; 01013 } 01014 01015 /* none found */ 01016 return NULL; 01017 } 01018 01019 /* Make the given NLA-Strip the active one within the given block */ 01020 void BKE_nlastrip_set_active (AnimData *adt, NlaStrip *strip) 01021 { 01022 NlaTrack *nlt; 01023 NlaStrip *nls; 01024 01025 /* sanity checks */ 01026 if (adt == NULL) 01027 return; 01028 01029 /* loop over tracks, deactivating*/ 01030 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01031 for (nls= nlt->strips.first; nls; nls= nls->next) { 01032 if (nls != strip) 01033 nls->flag &= ~NLASTRIP_FLAG_ACTIVE; 01034 else 01035 nls->flag |= NLASTRIP_FLAG_ACTIVE; 01036 } 01037 } 01038 } 01039 01040 01041 /* Does the given NLA-strip fall within the given bounds (times)? */ 01042 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max) 01043 { 01044 const float stripLen= (strip) ? strip->end - strip->start : 0.0f; 01045 const float boundsLen= (float)fabs(max - min); 01046 01047 /* sanity checks */ 01048 if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f)) 01049 return 0; 01050 01051 /* only ok if at least part of the strip is within the bounding window 01052 * - first 2 cases cover when the strip length is less than the bounding area 01053 * - second 2 cases cover when the strip length is greater than the bounding area 01054 */ 01055 if ( (stripLen < boundsLen) && 01056 !(IN_RANGE(strip->start, min, max) || 01057 IN_RANGE(strip->end, min, max)) ) 01058 { 01059 return 0; 01060 } 01061 if ( (stripLen > boundsLen) && 01062 !(IN_RANGE(min, strip->start, strip->end) || 01063 IN_RANGE(max, strip->start, strip->end)) ) 01064 { 01065 return 0; 01066 } 01067 01068 /* should be ok! */ 01069 return 1; 01070 } 01071 01072 /* Recalculate the start and end frames for the current strip, after changing 01073 * the extents of the action or the mapping (repeats or scale factor) info 01074 */ 01075 void BKE_nlastrip_recalculate_bounds (NlaStrip *strip) 01076 { 01077 float actlen, mapping; 01078 01079 /* sanity checks 01080 * - must have a strip 01081 * - can only be done for action clips 01082 */ 01083 if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP)) 01084 return; 01085 01086 /* calculate new length factors */ 01087 actlen= strip->actend - strip->actstart; 01088 if (IS_EQF(actlen, 0.0f)) actlen= 1.0f; 01089 01090 mapping= strip->scale * strip->repeat; 01091 01092 /* adjust endpoint of strip in response to this */ 01093 if (IS_EQF(mapping, 0.0f) == 0) 01094 strip->end = (actlen * mapping) + strip->start; 01095 } 01096 01097 /* Is the given NLA-strip the first one to occur for the given AnimData block */ 01098 // TODO: make this an api method if necesary, but need to add prefix first 01099 static short nlastrip_is_first (AnimData *adt, NlaStrip *strip) 01100 { 01101 NlaTrack *nlt; 01102 NlaStrip *ns; 01103 01104 /* sanity checks */ 01105 if ELEM(NULL, adt, strip) 01106 return 0; 01107 01108 /* check if strip has any strips before it */ 01109 if (strip->prev) 01110 return 0; 01111 01112 /* check other tracks to see if they have a strip that's earlier */ 01113 // TODO: or should we check that the strip's track is also the first? 01114 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01115 /* only check the first strip, assuming that they're all in order */ 01116 ns= nlt->strips.first; 01117 if (ns) { 01118 if (ns->start < strip->start) 01119 return 0; 01120 } 01121 } 01122 01123 /* should be first now */ 01124 return 1; 01125 } 01126 01127 /* Animated Strips ------------------------------------------- */ 01128 01129 /* Check if the given NLA-Track has any strips with own F-Curves */ 01130 short BKE_nlatrack_has_animated_strips (NlaTrack *nlt) 01131 { 01132 NlaStrip *strip; 01133 01134 /* sanity checks */ 01135 if ELEM(NULL, nlt, nlt->strips.first) 01136 return 0; 01137 01138 /* check each strip for F-Curves only (don't care about whether the flags are set) */ 01139 for (strip= nlt->strips.first; strip; strip= strip->next) { 01140 if (strip->fcurves.first) 01141 return 1; 01142 } 01143 01144 /* none found */ 01145 return 0; 01146 } 01147 01148 /* Check if given NLA-Tracks have any strips with own F-Curves */ 01149 short BKE_nlatracks_have_animated_strips (ListBase *tracks) 01150 { 01151 NlaTrack *nlt; 01152 01153 /* sanity checks */ 01154 if ELEM(NULL, tracks, tracks->first) 01155 return 0; 01156 01157 /* check each track, stopping on the first hit */ 01158 for (nlt= tracks->first; nlt; nlt= nlt->next) { 01159 if (BKE_nlatrack_has_animated_strips(nlt)) 01160 return 1; 01161 } 01162 01163 /* none found */ 01164 return 0; 01165 } 01166 01167 /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/ 01168 void BKE_nlastrip_validate_fcurves (NlaStrip *strip) 01169 { 01170 FCurve *fcu; 01171 01172 /* sanity checks */ 01173 if (strip == NULL) 01174 return; 01175 01176 /* if controlling influence... */ 01177 if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) { 01178 /* try to get F-Curve */ 01179 fcu= list_find_fcurve(&strip->fcurves, "influence", 0); 01180 01181 /* add one if not found */ 01182 if (fcu == NULL) { 01183 /* make new F-Curve */ 01184 fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve"); 01185 BLI_addtail(&strip->fcurves, fcu); 01186 01187 /* set default flags */ 01188 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); 01189 01190 /* store path - make copy, and store that */ 01191 fcu->rna_path= BLI_strdupn("influence", 9); 01192 01193 // TODO: insert a few keyframes to ensure default behaviour? 01194 } 01195 } 01196 01197 /* if controlling time... */ 01198 if (strip->flag & NLASTRIP_FLAG_USR_TIME) { 01199 /* try to get F-Curve */ 01200 fcu= list_find_fcurve(&strip->fcurves, "strip_time", 0); 01201 01202 /* add one if not found */ 01203 if (fcu == NULL) { 01204 /* make new F-Curve */ 01205 fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve"); 01206 BLI_addtail(&strip->fcurves, fcu); 01207 01208 /* set default flags */ 01209 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); 01210 01211 /* store path - make copy, and store that */ 01212 fcu->rna_path= BLI_strdupn("strip_time", 10); 01213 01214 // TODO: insert a few keyframes to ensure default behaviour? 01215 } 01216 } 01217 } 01218 01219 /* Sanity Validation ------------------------------------ */ 01220 01221 static int nla_editbone_name_check(void *arg, const char *name) 01222 { 01223 return BLI_ghash_haskey((GHash *)arg, (void *)name); 01224 } 01225 01226 /* Find (and set) a unique name for a strip from the whole AnimData block 01227 * Uses a similar method to the BLI method, but is implemented differently 01228 * as we need to ensure that the name is unique over several lists of tracks, 01229 * not just a single track. 01230 */ 01231 void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip) 01232 { 01233 GHash *gh; 01234 NlaStrip *tstrip; 01235 NlaTrack *nlt; 01236 01237 /* sanity checks */ 01238 if ELEM(NULL, adt, strip) 01239 return; 01240 01241 /* give strip a default name if none already */ 01242 if (strip->name[0]==0) { 01243 switch (strip->type) { 01244 case NLASTRIP_TYPE_CLIP: /* act-clip */ 01245 sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>")); 01246 break; 01247 case NLASTRIP_TYPE_TRANSITION: /* transition */ 01248 sprintf(strip->name, "Transition"); 01249 break; 01250 case NLASTRIP_TYPE_META: /* meta */ 01251 sprintf(strip->name, "Meta"); 01252 break; 01253 default: 01254 sprintf(strip->name, "NLA Strip"); 01255 break; 01256 } 01257 } 01258 01259 /* build a hash-table of all the strips in the tracks 01260 * - this is easier than iterating over all the tracks+strips hierarchy everytime 01261 * (and probably faster) 01262 */ 01263 gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "nlastrip_validate_name gh"); 01264 01265 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01266 for (tstrip= nlt->strips.first; tstrip; tstrip= tstrip->next) { 01267 /* don't add the strip of interest */ 01268 if (tstrip == strip) 01269 continue; 01270 01271 /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */ 01272 BLI_ghash_insert(gh, tstrip->name, tstrip); 01273 } 01274 } 01275 01276 /* if the hash-table has a match for this name, try other names... 01277 * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :) 01278 */ 01279 BLI_uniquename_cb(nla_editbone_name_check, (void *)gh, "NlaStrip", '.', strip->name, sizeof(strip->name)); 01280 01281 /* free the hash... */ 01282 BLI_ghash_free(gh, NULL, NULL); 01283 } 01284 01285 /* ---- */ 01286 01287 /* Get strips which overlap the given one at the start/end of its range 01288 * - strip: strip that we're finding overlaps for 01289 * - track: nla-track that the overlapping strips should be found from 01290 * - start, end: frames for the offending endpoints 01291 */ 01292 static void nlastrip_get_endpoint_overlaps (NlaStrip *strip, NlaTrack *track, float **start, float **end) 01293 { 01294 NlaStrip *nls; 01295 01296 /* find strips that overlap over the start/end of the given strip, 01297 * but which don't cover the entire length 01298 */ 01299 // TODO: this scheme could get quite slow for doing this on many strips... 01300 for (nls= track->strips.first; nls; nls= nls->next) { 01301 /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */ 01302 if ((nls->start <= strip->start) && (nls->end >= strip->end)) { 01303 *start= NULL; 01304 *end= NULL; 01305 return; 01306 } 01307 01308 /* check if strip doesn't even occur anywhere near... */ 01309 if (nls->end < strip->start) 01310 continue; /* skip checking this strip... not worthy of mention */ 01311 if (nls->start > strip->end) 01312 return; /* the range we're after has already passed */ 01313 01314 /* if this strip is not part of an island of continuous strips, it can be used 01315 * - this check needs to be done for each end of the strip we try and use... 01316 */ 01317 if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end)==0) { 01318 if ((nls->end > strip->start) && (nls->end < strip->end)) 01319 *start= &nls->end; 01320 } 01321 if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start)==0) { 01322 if ((nls->start < strip->end) && (nls->start > strip->start)) 01323 *end= &nls->start; 01324 } 01325 } 01326 } 01327 01328 /* Determine auto-blending for the given strip */ 01329 static void BKE_nlastrip_validate_autoblends (NlaTrack *nlt, NlaStrip *nls) 01330 { 01331 float *ps=NULL, *pe=NULL; 01332 float *ns=NULL, *ne=NULL; 01333 01334 /* sanity checks */ 01335 if ELEM(NULL, nls, nlt) 01336 return; 01337 if ((nlt->prev == NULL) && (nlt->next == NULL)) 01338 return; 01339 if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS)==0) 01340 return; 01341 01342 /* get test ranges */ 01343 if (nlt->prev) 01344 nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe); 01345 if (nlt->next) 01346 nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne); 01347 01348 /* set overlaps for this strip 01349 * - don't use the values obtained though if the end in question 01350 * is directly followed/preceeded by another strip, forming an 01351 * 'island' of continuous strips 01352 */ 01353 if ( (ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start)==0) ) 01354 { 01355 /* start overlaps - pick the largest overlap */ 01356 if ( ((ps && ns) && (*ps > *ns)) || (ps) ) 01357 nls->blendin= *ps - nls->start; 01358 else 01359 nls->blendin= *ns - nls->start; 01360 } 01361 else /* no overlap allowed/needed */ 01362 nls->blendin= 0.0f; 01363 01364 if ( (pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end)==0) ) 01365 { 01366 /* end overlaps - pick the largest overlap */ 01367 if ( ((pe && ne) && (*pe > *ne)) || (pe) ) 01368 nls->blendout= nls->end - *pe; 01369 else 01370 nls->blendout= nls->end - *ne; 01371 } 01372 else /* no overlap allowed/needed */ 01373 nls->blendout= 0.0f; 01374 } 01375 01376 /* Ensure that auto-blending and other settings are set correctly */ 01377 void BKE_nla_validate_state (AnimData *adt) 01378 { 01379 NlaStrip *strip, *fstrip=NULL; 01380 NlaTrack *nlt; 01381 01382 /* sanity checks */ 01383 if ELEM(NULL, adt, adt->nla_tracks.first) 01384 return; 01385 01386 /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */ 01387 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01388 for (strip= nlt->strips.first; strip; strip= strip->next) { 01389 /* auto-blending first */ 01390 BKE_nlastrip_validate_autoblends(nlt, strip); 01391 01392 /* extend mode - find first strip */ 01393 if ((fstrip == NULL) || (strip->start < fstrip->start)) 01394 fstrip= strip; 01395 } 01396 } 01397 01398 /* second pass over the strips to adjust the extend-mode to fix any problems */ 01399 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01400 for (strip= nlt->strips.first; strip; strip= strip->next) { 01401 /* apart from 'nothing' option which user has to explicitly choose, we don't really know if 01402 * we should be overwriting the extend setting (but assume that's what the user wanted) 01403 */ 01404 // TODO: 1 solution is to tie this in with auto-blending... 01405 if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) { 01406 if (strip == fstrip) 01407 strip->extendmode= NLASTRIP_EXTEND_HOLD; 01408 else 01409 strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD; 01410 } 01411 } 01412 } 01413 } 01414 01415 /* Core Tools ------------------------------------------- */ 01416 01417 /* For the given AnimData block, add the active action to the NLA 01418 * stack (i.e. 'push-down' action). The UI should only allow this 01419 * for normal editing only (i.e. not in editmode for some strip's action), 01420 * so no checks for this are performed. 01421 */ 01422 // TODO: maybe we should have checks for this too... 01423 void BKE_nla_action_pushdown (AnimData *adt) 01424 { 01425 NlaStrip *strip; 01426 01427 /* sanity checks */ 01428 // TODO: need to report the error for this 01429 if ELEM(NULL, adt, adt->action) 01430 return; 01431 01432 /* if the action is empty, we also shouldn't try to add to stack, 01433 * as that will cause us grief down the track 01434 */ 01435 // TODO: what about modifiers? 01436 if (action_has_motion(adt->action) == 0) { 01437 printf("BKE_nla_action_pushdown(): action has no data \n"); 01438 return; 01439 } 01440 01441 /* add a new NLA strip to the track, which references the active action */ 01442 strip= add_nlastrip_to_stack(adt, adt->action); 01443 01444 /* do other necessary work on strip */ 01445 if (strip) { 01446 /* clear reference to action now that we've pushed it onto the stack */ 01447 id_us_min(&adt->action->id); 01448 adt->action= NULL; 01449 01450 /* if the strip is the first one in the track it lives in, check if there 01451 * are strips in any other tracks that may be before this, and set the extend 01452 * mode accordingly 01453 */ 01454 if (nlastrip_is_first(adt, strip) == 0) { 01455 /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD, 01456 * so that it doesn't override strips in previous tracks 01457 */ 01458 // FIXME: this needs to be more automated, since user can rearrange strips 01459 strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD; 01460 } 01461 01462 /* make strip the active one... */ 01463 BKE_nlastrip_set_active(adt, strip); 01464 } 01465 } 01466 01467 01468 /* Find the active strip + track combo, and set them up as the tweaking track, 01469 * and return if successful or not. 01470 */ 01471 short BKE_nla_tweakmode_enter (AnimData *adt) 01472 { 01473 NlaTrack *nlt, *activeTrack=NULL; 01474 NlaStrip *strip, *activeStrip=NULL; 01475 01476 /* verify that data is valid */ 01477 if ELEM(NULL, adt, adt->nla_tracks.first) 01478 return 0; 01479 01480 /* if block is already in tweakmode, just leave, but we should report 01481 * that this block is in tweakmode (as our returncode) 01482 */ 01483 if (adt->flag & ADT_NLA_EDIT_ON) 01484 return 1; 01485 01486 /* go over the tracks, finding the active one, and its active strip 01487 * - if we cannot find both, then there's nothing to do 01488 */ 01489 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01490 /* check if active */ 01491 if (nlt->flag & NLATRACK_ACTIVE) { 01492 /* store reference to this active track */ 01493 activeTrack= nlt; 01494 01495 /* now try to find active strip */ 01496 activeStrip= BKE_nlastrip_find_active(nlt); 01497 break; 01498 } 01499 } 01500 if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) { 01501 if (G.f & G_DEBUG) { 01502 printf("NLA tweakmode enter - neither active requirement found \n"); 01503 printf("\tactiveTrack = %p, activeStrip = %p \n", (void *)activeTrack, (void *)activeStrip); 01504 } 01505 return 0; 01506 } 01507 01508 /* go over all the tracks up to the active one, tagging each strip that uses the same 01509 * action as the active strip, but leaving everything else alone 01510 */ 01511 for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) { 01512 for (strip= nlt->strips.first; strip; strip= strip->next) { 01513 if (strip->act == activeStrip->act) 01514 strip->flag |= NLASTRIP_FLAG_TWEAKUSER; 01515 else 01516 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; 01517 } 01518 } 01519 01520 01521 /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 01522 * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on 01523 */ 01524 for (nlt= activeTrack; nlt; nlt= nlt->next) 01525 nlt->flag |= NLATRACK_DISABLED; 01526 01527 /* handle AnimData level changes: 01528 * - 'real' active action to temp storage (no need to change user-counts) 01529 * - action of active strip set to be the 'active action', and have its usercount incremented 01530 * - editing-flag for this AnimData block should also get turned on (for more efficient restoring) 01531 * - take note of the active strip for mapping-correction of keyframes in the action being edited 01532 */ 01533 adt->tmpact= adt->action; 01534 adt->action= activeStrip->act; 01535 adt->actstrip= activeStrip; 01536 id_us_plus(&activeStrip->act->id); 01537 adt->flag |= ADT_NLA_EDIT_ON; 01538 01539 /* done! */ 01540 return 1; 01541 } 01542 01543 /* Exit tweakmode for this AnimData block */ 01544 void BKE_nla_tweakmode_exit (AnimData *adt) 01545 { 01546 NlaStrip *strip; 01547 NlaTrack *nlt; 01548 01549 /* verify that data is valid */ 01550 if ELEM(NULL, adt, adt->nla_tracks.first) 01551 return; 01552 01553 /* hopefully the flag is correct - skip if not on */ 01554 if ((adt->flag & ADT_NLA_EDIT_ON) == 0) 01555 return; 01556 01557 // TODO: need to sync the user-strip with the new state of the action! 01558 01559 /* for all Tracks, clear the 'disabled' flag 01560 * for all Strips, clear the 'tweak-user' flag 01561 */ 01562 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { 01563 nlt->flag &= ~NLATRACK_DISABLED; 01564 01565 for (strip= nlt->strips.first; strip; strip= strip->next) 01566 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; 01567 } 01568 01569 /* handle AnimData level changes: 01570 * - 'temporary' active action needs its usercount decreased, since we're removing this reference 01571 * - 'real' active action is restored from storage 01572 * - storage pointer gets cleared (to avoid having bad notes hanging around) 01573 * - editing-flag for this AnimData block should also get turned off 01574 * - clear pointer to active strip 01575 */ 01576 if (adt->action) adt->action->id.us--; 01577 adt->action= adt->tmpact; 01578 adt->tmpact= NULL; 01579 adt->actstrip= NULL; 01580 adt->flag &= ~ADT_NLA_EDIT_ON; 01581 } 01582 01583 /* Baking Tools ------------------------------------------- */ 01584 01585 static void BKE_nla_bake (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag)) 01586 { 01587 01588 /* verify that data is valid 01589 * 1) Scene and AnimData must be provided 01590 * 2) there must be tracks to merge... 01591 */ 01592 if ELEM3(NULL, scene, adt, adt->nla_tracks.first) 01593 return; 01594 01595 /* if animdata currently has an action, 'push down' this onto the stack first */ 01596 if (adt->action) 01597 BKE_nla_action_pushdown(adt); 01598 01599 /* get range of motion to bake, and the channels involved... */ 01600 01601 /* temporarily mute the action, and start keying to it */ 01602 01603 /* start keying... */ 01604 01605 /* unmute the action */ 01606 } 01607 01608 /* *************************************************** */