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