1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <float.h>
25 #include <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "CLG_log.h"
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_ghash.h"
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38 #include "BLI_string_utils.h"
39 #include "BLI_utildefines.h"
40
41 #include "BLT_translation.h"
42
43 #include "DNA_anim_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_sound_types.h"
46 #include "DNA_speaker_types.h"
47
48 #include "BKE_action.h"
49 #include "BKE_fcurve.h"
50 #include "BKE_global.h"
51 #include "BKE_lib_id.h"
52 #include "BKE_lib_query.h"
53 #include "BKE_main.h"
54 #include "BKE_nla.h"
55 #include "BKE_sound.h"
56
57 #include "BLO_read_write.h"
58
59 #include "RNA_access.h"
60 #include "nla_private.h"
61
62 static CLG_LogRef LOG = {"bke.nla"};
63
64 /* *************************************************** */
65 /* Data Management */
66
67 /* Freeing ------------------------------------------- */
68
69 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
70 * and the strip itself.
71 */
BKE_nlastrip_free(ListBase * strips,NlaStrip * strip,bool do_id_user)72 void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
73 {
74 NlaStrip *cs, *csn;
75
76 /* sanity checks */
77 if (strip == NULL) {
78 return;
79 }
80
81 /* free child-strips */
82 for (cs = strip->strips.first; cs; cs = csn) {
83 csn = cs->next;
84 BKE_nlastrip_free(&strip->strips, cs, do_id_user);
85 }
86
87 /* remove reference to action */
88 if (strip->act != NULL && do_id_user) {
89 id_us_min(&strip->act->id);
90 }
91
92 /* free remapping info */
93 // if (strip->remap)
94 // BKE_animremap_free();
95
96 /* free own F-Curves */
97 BKE_fcurves_free(&strip->fcurves);
98
99 /* free own F-Modifiers */
100 free_fmodifiers(&strip->modifiers);
101
102 /* free the strip itself */
103 if (strips) {
104 BLI_freelinkN(strips, strip);
105 }
106 else {
107 MEM_freeN(strip);
108 }
109 }
110
111 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
112 * and the track itself.
113 */
BKE_nlatrack_free(ListBase * tracks,NlaTrack * nlt,bool do_id_user)114 void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
115 {
116 NlaStrip *strip, *stripn;
117
118 /* sanity checks */
119 if (nlt == NULL) {
120 return;
121 }
122
123 /* free strips */
124 for (strip = nlt->strips.first; strip; strip = stripn) {
125 stripn = strip->next;
126 BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
127 }
128
129 /* free NLA track itself now */
130 if (tracks) {
131 BLI_freelinkN(tracks, nlt);
132 }
133 else {
134 MEM_freeN(nlt);
135 }
136 }
137
138 /* Free the elements of type NLA Tracks provided in the given list, but do not free
139 * the list itself since that is not free-standing
140 */
BKE_nla_tracks_free(ListBase * tracks,bool do_id_user)141 void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
142 {
143 NlaTrack *nlt, *nltn;
144
145 /* sanity checks */
146 if (ELEM(NULL, tracks, tracks->first)) {
147 return;
148 }
149
150 /* free tracks one by one */
151 for (nlt = tracks->first; nlt; nlt = nltn) {
152 nltn = nlt->next;
153 BKE_nlatrack_free(tracks, nlt, do_id_user);
154 }
155
156 /* clear the list's pointers to be safe */
157 BLI_listbase_clear(tracks);
158 }
159
160 /* Copying ------------------------------------------- */
161
162 /**
163 * Copy NLA strip
164 *
165 * \param use_same_action: When true, the existing action is used (instead of being duplicated)
166 * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
167 * flags in BKE_lib_id.h
168 */
BKE_nlastrip_copy(Main * bmain,NlaStrip * strip,const bool use_same_action,const int flag)169 NlaStrip *BKE_nlastrip_copy(Main *bmain,
170 NlaStrip *strip,
171 const bool use_same_action,
172 const int flag)
173 {
174 NlaStrip *strip_d;
175 NlaStrip *cs, *cs_d;
176
177 const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
178
179 /* sanity check */
180 if (strip == NULL) {
181 return NULL;
182 }
183
184 /* make a copy */
185 strip_d = MEM_dupallocN(strip);
186 strip_d->next = strip_d->prev = NULL;
187
188 /* handle action */
189 if (strip_d->act) {
190 if (use_same_action) {
191 if (do_id_user) {
192 /* increase user-count of action */
193 id_us_plus(&strip_d->act->id);
194 }
195 }
196 else {
197 /* use a copy of the action instead (user count shouldn't have changed yet) */
198 BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag);
199 }
200 }
201
202 /* copy F-Curves and modifiers */
203 BKE_fcurves_copy(&strip_d->fcurves, &strip->fcurves);
204 copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
205
206 /* make a copy of all the child-strips, one at a time */
207 BLI_listbase_clear(&strip_d->strips);
208
209 for (cs = strip->strips.first; cs; cs = cs->next) {
210 cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
211 BLI_addtail(&strip_d->strips, cs_d);
212 }
213
214 /* return the strip */
215 return strip_d;
216 }
217
218 /**
219 * Copy a single NLA Track.
220 * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
221 * flags in BKE_lib_id.h
222 */
BKE_nlatrack_copy(Main * bmain,NlaTrack * nlt,const bool use_same_actions,const int flag)223 NlaTrack *BKE_nlatrack_copy(Main *bmain,
224 NlaTrack *nlt,
225 const bool use_same_actions,
226 const int flag)
227 {
228 NlaStrip *strip, *strip_d;
229 NlaTrack *nlt_d;
230
231 /* sanity check */
232 if (nlt == NULL) {
233 return NULL;
234 }
235
236 /* make a copy */
237 nlt_d = MEM_dupallocN(nlt);
238 nlt_d->next = nlt_d->prev = NULL;
239
240 /* make a copy of all the strips, one at a time */
241 BLI_listbase_clear(&nlt_d->strips);
242
243 for (strip = nlt->strips.first; strip; strip = strip->next) {
244 strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
245 BLI_addtail(&nlt_d->strips, strip_d);
246 }
247
248 /* return the copy */
249 return nlt_d;
250 }
251
252 /**
253 * Copy all NLA data.
254 * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
255 * flags in BKE_lib_id.h
256 */
BKE_nla_tracks_copy(Main * bmain,ListBase * dst,ListBase * src,const int flag)257 void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag)
258 {
259 NlaTrack *nlt, *nlt_d;
260
261 /* sanity checks */
262 if (ELEM(NULL, dst, src)) {
263 return;
264 }
265
266 /* clear out the destination list first for precautions... */
267 BLI_listbase_clear(dst);
268
269 /* copy each NLA-track, one at a time */
270 for (nlt = src->first; nlt; nlt = nlt->next) {
271 /* make a copy, and add the copy to the destination list */
272 // XXX: we need to fix this sometime
273 nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
274 BLI_addtail(dst, nlt_d);
275 }
276 }
277
278 /* Adding ------------------------------------------- */
279
280 /* Add a NLA Track to the given AnimData
281 * - prev: NLA-Track to add the new one after
282 */
BKE_nlatrack_add(AnimData * adt,NlaTrack * prev)283 NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
284 {
285 NlaTrack *nlt;
286
287 /* sanity checks */
288 if (adt == NULL) {
289 return NULL;
290 }
291
292 /* allocate new track */
293 nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack");
294
295 /* set settings requiring the track to not be part of the stack yet */
296 nlt->flag = NLATRACK_SELECTED;
297 nlt->index = BLI_listbase_count(&adt->nla_tracks);
298
299 /* add track to stack, and make it the active one */
300 if (prev) {
301 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
302 }
303 else {
304 BLI_addtail(&adt->nla_tracks, nlt);
305 }
306 BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
307
308 /* must have unique name, but we need to seed this */
309 strcpy(nlt->name, "NlaTrack");
310 BLI_uniquename(
311 &adt->nla_tracks, nlt, DATA_("NlaTrack"), '.', offsetof(NlaTrack, name), sizeof(nlt->name));
312
313 /* return the new track */
314 return nlt;
315 }
316
317 /* Create a NLA Strip referencing the given Action */
BKE_nlastrip_new(bAction * act)318 NlaStrip *BKE_nlastrip_new(bAction *act)
319 {
320 NlaStrip *strip;
321
322 /* sanity checks */
323 if (act == NULL) {
324 return NULL;
325 }
326
327 /* allocate new strip */
328 strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
329
330 /* generic settings
331 * - selected flag to highlight this to the user
332 * - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects
333 * - (XXX) synchronization of strip-length in accordance with changes to action-length
334 * is not done though, since this should only really happens in editmode for strips now
335 * though this decision is still subject to further review...
336 */
337 strip->flag = NLASTRIP_FLAG_SELECT;
338
339 /* assign the action reference */
340 strip->act = act;
341 id_us_plus(&act->id);
342
343 /* determine initial range
344 * - strip length cannot be 0... ever...
345 */
346 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
347
348 strip->start = strip->actstart;
349 strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
350 (strip->actend);
351
352 /* strip should be referenced as-is */
353 strip->scale = 1.0f;
354 strip->repeat = 1.0f;
355
356 /* return the new strip */
357 return strip;
358 }
359
360 /* Add new NLA-strip to the top of the NLA stack - i.e.
361 * into the last track if space, or a new one otherwise. */
BKE_nlastack_add_strip(AnimData * adt,bAction * act)362 NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
363 {
364 NlaStrip *strip;
365 NlaTrack *nlt;
366
367 /* sanity checks */
368 if (ELEM(NULL, adt, act)) {
369 return NULL;
370 }
371
372 /* create a new NLA strip */
373 strip = BKE_nlastrip_new(act);
374 if (strip == NULL) {
375 return NULL;
376 }
377
378 /* firstly try adding strip to last track, but if that fails, add to a new track */
379 if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
380 /* trying to add to the last track failed (no track or no space),
381 * so add a new track to the stack, and add to that...
382 */
383 nlt = BKE_nlatrack_add(adt, NULL);
384 BKE_nlatrack_add_strip(nlt, strip);
385 }
386
387 /* automatically name it too */
388 BKE_nlastrip_validate_name(adt, strip);
389
390 /* returns the strip added */
391 return strip;
392 }
393
394 /* Add a NLA Strip referencing the given speaker's sound */
BKE_nla_add_soundstrip(Main * bmain,Scene * scene,Speaker * speaker)395 NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
396 {
397 NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
398
399 /* if speaker has a sound, set the strip length to the length of the sound,
400 * otherwise default to length of 10 frames
401 */
402 #ifdef WITH_AUDASPACE
403 if (speaker->sound) {
404 SoundInfo info;
405 if (BKE_sound_info_get(bmain, speaker->sound, &info)) {
406 strip->end = (float)ceil((double)info.length * FPS);
407 }
408 }
409 else
410 #endif
411 {
412 strip->end = 10.0f;
413 /* quiet compiler warnings */
414 UNUSED_VARS(bmain, scene, speaker);
415 }
416
417 /* general settings */
418 strip->type = NLASTRIP_TYPE_SOUND;
419
420 strip->flag = NLASTRIP_FLAG_SELECT;
421 strip->extendmode = NLASTRIP_EXTEND_NOTHING; /* nothing to extend... */
422
423 /* strip should be referenced as-is */
424 strip->scale = 1.0f;
425 strip->repeat = 1.0f;
426
427 /* return this strip */
428 return strip;
429 }
430
431 /** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
432 * `IDTypeInfo` structure). */
BKE_nla_strip_foreach_id(NlaStrip * strip,LibraryForeachIDData * data)433 void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
434 {
435 BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
436
437 LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) {
438 BKE_fcurve_foreach_id(fcu, data);
439 }
440
441 LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
442 BKE_nla_strip_foreach_id(substrip, data);
443 }
444 }
445
446 /* *************************************************** */
447 /* NLA Evaluation <-> Editing Stuff */
448
449 /* Strip Mapping ------------------------------------- */
450
451 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
452 * invert = convert action-strip time to global time
453 */
nlastrip_get_frame_actionclip(NlaStrip * strip,float cframe,short mode)454 static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short mode)
455 {
456 float actlength, scale;
457 // float repeat; // UNUSED
458
459 /* get number of repeats */
460 if (IS_EQF(strip->repeat, 0.0f)) {
461 strip->repeat = 1.0f;
462 }
463 // repeat = strip->repeat; // UNUSED
464
465 /* scaling */
466 if (IS_EQF(strip->scale, 0.0f)) {
467 strip->scale = 1.0f;
468 }
469
470 /* Scale must be positive - we've got a special flag for reversing. */
471 scale = fabsf(strip->scale);
472
473 /* length of referenced action */
474 actlength = strip->actend - strip->actstart;
475 if (IS_EQF(actlength, 0.0f)) {
476 actlength = 1.0f;
477 }
478
479 /* reversed = play strip backwards */
480 if (strip->flag & NLASTRIP_FLAG_REVERSE) {
481 /* FIXME: this won't work right with Graph Editor? */
482 if (mode == NLATIME_CONVERT_MAP) {
483 return strip->end - scale * (cframe - strip->actstart);
484 }
485 if (mode == NLATIME_CONVERT_UNMAP) {
486 return (strip->end + (strip->actstart * scale - cframe)) / scale;
487 }
488 /* if (mode == NLATIME_CONVERT_EVAL) */
489 if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
490 /* This case prevents the motion snapping back to the first frame at the end of the strip
491 * by catching the case where repeats is a whole number, which means that the end of the
492 * strip could also be interpreted as the end of the start of a repeat. */
493 return strip->actstart;
494 }
495
496 /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
497 * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
498 */
499 return strip->actend - fmodf(cframe - strip->start, actlength * scale) / scale;
500 }
501
502 if (mode == NLATIME_CONVERT_MAP) {
503 return strip->start + scale * (cframe - strip->actstart);
504 }
505 if (mode == NLATIME_CONVERT_UNMAP) {
506 return strip->actstart + (cframe - strip->start) / scale;
507 }
508 /* if (mode == NLATIME_CONVERT_EVAL) */
509 if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
510 /* This case prevents the motion snapping back to the first frame at the end of the strip
511 * by catching the case where repeats is a whole number, which means that the end of the
512 * strip could also be interpreted as the end of the start of a repeat. */
513 return strip->actend;
514 }
515
516 /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
517 * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
518 */
519 return strip->actstart + fmodf(cframe - strip->start, actlength * scale) / scale;
520 }
521
522 /* non clipped mapping for strip-time <-> global time (for Transitions)
523 * invert = convert action-strip time to global time
524 */
nlastrip_get_frame_transition(NlaStrip * strip,float cframe,short mode)525 static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short mode)
526 {
527 float length;
528
529 /* length of strip */
530 length = strip->end - strip->start;
531
532 /* reversed = play strip backwards */
533 if (strip->flag & NLASTRIP_FLAG_REVERSE) {
534 if (mode == NLATIME_CONVERT_MAP) {
535 return strip->end - (length * cframe);
536 }
537
538 return (strip->end - cframe) / length;
539 }
540
541 if (mode == NLATIME_CONVERT_MAP) {
542 return (length * cframe) + strip->start;
543 }
544
545 return (cframe - strip->start) / length;
546 }
547
548 /* non clipped mapping for strip-time <-> global time
549 * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
550 *
551 * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
552 * but should not be directly relied on for stuff which interacts with editors
553 */
nlastrip_get_frame(NlaStrip * strip,float cframe,short mode)554 float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
555 {
556 switch (strip->type) {
557 case NLASTRIP_TYPE_META: /* Meta - for now, does the same as transition
558 * (is really just an empty container). */
559 case NLASTRIP_TYPE_TRANSITION: /* transition */
560 return nlastrip_get_frame_transition(strip, cframe, mode);
561
562 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
563 default:
564 return nlastrip_get_frame_actionclip(strip, cframe, mode);
565 }
566 }
567
568 /* Non clipped mapping for strip-time <-> global time
569 * mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
570 *
571 * Public API method - perform this mapping using the given AnimData block
572 * and perform any necessary sanity checks on the value
573 */
BKE_nla_tweakedit_remap(AnimData * adt,float cframe,short mode)574 float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
575 {
576 NlaStrip *strip;
577
578 /* sanity checks
579 * - obviously we've got to have some starting data
580 * - when not in tweakmode, the active Action does not have any scaling applied :)
581 * - when in tweakmode, if the no-mapping flag is set, do not map
582 */
583 if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON) == 0 || (adt->flag & ADT_NLA_EDIT_NOMAP)) {
584 return cframe;
585 }
586
587 /* if the active-strip info has been stored already, access this, otherwise look this up
588 * and store for (very probable) future usage
589 */
590 if (adt->act_track == NULL) {
591 if (adt->actstrip) {
592 adt->act_track = BKE_nlatrack_find_tweaked(adt);
593 }
594 else {
595 adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
596 }
597 }
598 if (adt->actstrip == NULL) {
599 adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
600 }
601 strip = adt->actstrip;
602
603 /* Sanity checks:
604 * - In rare cases, we may not be able to find this strip for some reason (internal error)
605 * - For now, if the user has defined a curve to control the time, this correction cannot be
606 * performed reliably.
607 */
608 if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME)) {
609 return cframe;
610 }
611
612 /* perform the correction now... */
613 return nlastrip_get_frame(strip, cframe, mode);
614 }
615
616 /* *************************************************** */
617 /* NLA API */
618
619 /* List of Strips ------------------------------------ */
620 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
621
622 /* Check if there is any space in the given list to add the given strip */
BKE_nlastrips_has_space(ListBase * strips,float start,float end)623 bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
624 {
625 NlaStrip *strip;
626
627 /* sanity checks */
628 if ((strips == NULL) || IS_EQF(start, end)) {
629 return false;
630 }
631 if (start > end) {
632 puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
633 SWAP(float, start, end);
634 }
635
636 /* loop over NLA strips checking for any overlaps with this area... */
637 for (strip = strips->first; strip; strip = strip->next) {
638 /* if start frame of strip is past the target end-frame, that means that
639 * we've gone past the window we need to check for, so things are fine
640 */
641 if (strip->start >= end) {
642 return true;
643 }
644
645 /* if the end of the strip is greater than either of the boundaries, the range
646 * must fall within the extents of the strip
647 */
648 if ((strip->end > start) || (strip->end > end)) {
649 return false;
650 }
651 }
652
653 /* if we are still here, we haven't encountered any overlapping strips */
654 return true;
655 }
656
657 /* Rearrange the strips in the track so that they are always in order
658 * (usually only needed after a strip has been moved)
659 */
BKE_nlastrips_sort_strips(ListBase * strips)660 void BKE_nlastrips_sort_strips(ListBase *strips)
661 {
662 ListBase tmp = {NULL, NULL};
663 NlaStrip *strip, *sstrip, *stripn;
664
665 /* sanity checks */
666 if (ELEM(NULL, strips, strips->first)) {
667 return;
668 }
669
670 /* we simply perform insertion sort on this list, since it is assumed that per track,
671 * there are only likely to be at most 5-10 strips
672 */
673 for (strip = strips->first; strip; strip = stripn) {
674 short not_added = 1;
675
676 stripn = strip->next;
677
678 /* remove this strip from the list, and add it to the new list, searching from the end of
679 * the list, assuming that the lists are in order
680 */
681 BLI_remlink(strips, strip);
682
683 for (sstrip = tmp.last; sstrip; sstrip = sstrip->prev) {
684 /* check if add after */
685 if (sstrip->end <= strip->start) {
686 BLI_insertlinkafter(&tmp, sstrip, strip);
687 not_added = 0;
688 break;
689 }
690 }
691
692 /* add before first? */
693 if (not_added) {
694 BLI_addhead(&tmp, strip);
695 }
696 }
697
698 /* reassign the start and end points of the strips */
699 strips->first = tmp.first;
700 strips->last = tmp.last;
701 }
702
703 /* Add the given NLA-Strip to the given list of strips, assuming that it
704 * isn't currently a member of another list
705 */
BKE_nlastrips_add_strip(ListBase * strips,NlaStrip * strip)706 bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
707 {
708 NlaStrip *ns;
709 bool not_added = true;
710
711 /* sanity checks */
712 if (ELEM(NULL, strips, strip)) {
713 return false;
714 }
715
716 /* check if any space to add */
717 if (BKE_nlastrips_has_space(strips, strip->start, strip->end) == 0) {
718 return false;
719 }
720
721 /* find the right place to add the strip to the nominated track */
722 for (ns = strips->first; ns; ns = ns->next) {
723 /* if current strip occurs after the new strip, add it before */
724 if (ns->start >= strip->end) {
725 BLI_insertlinkbefore(strips, ns, strip);
726 not_added = 0;
727 break;
728 }
729 }
730 if (not_added) {
731 /* just add to the end of the list of the strips then... */
732 BLI_addtail(strips, strip);
733 }
734
735 /* added... */
736 return true;
737 }
738
739 /* Meta-Strips ------------------------------------ */
740
741 /* Convert 'islands' (i.e. continuous string of) selected strips to be
742 * contained within 'Meta-Strips' which act as strips which contain strips.
743 * temp: are the meta-strips to be created 'temporary' ones used for transforms?
744 */
BKE_nlastrips_make_metas(ListBase * strips,bool is_temp)745 void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
746 {
747 NlaStrip *mstrip = NULL;
748 NlaStrip *strip, *stripn;
749
750 /* sanity checks */
751 if (ELEM(NULL, strips, strips->first)) {
752 return;
753 }
754
755 /* group all continuous chains of selected strips into meta-strips */
756 for (strip = strips->first; strip; strip = stripn) {
757 stripn = strip->next;
758
759 if (strip->flag & NLASTRIP_FLAG_SELECT) {
760 /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
761 if (mstrip == NULL) {
762 /* add a new meta-strip, and add it before the current strip that it will replace... */
763 mstrip = MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
764 mstrip->type = NLASTRIP_TYPE_META;
765 BLI_insertlinkbefore(strips, strip, mstrip);
766
767 /* set flags */
768 mstrip->flag = NLASTRIP_FLAG_SELECT;
769
770 /* set temp flag if appropriate (i.e. for transform-type editing) */
771 if (is_temp) {
772 mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
773 }
774
775 /* set default repeat/scale values to prevent warnings */
776 mstrip->repeat = mstrip->scale = 1.0f;
777
778 /* make its start frame be set to the start frame of the current strip */
779 mstrip->start = strip->start;
780 }
781
782 /* remove the selected strips from the track, and add to the meta */
783 BLI_remlink(strips, strip);
784 BLI_addtail(&mstrip->strips, strip);
785
786 /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
787 mstrip->end = strip->end;
788 }
789 else {
790 /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
791 * so stop adding strips to the current meta
792 */
793 mstrip = NULL;
794 }
795 }
796 }
797
798 /* Split a meta-strip into a set of normal strips */
BKE_nlastrips_clear_metastrip(ListBase * strips,NlaStrip * strip)799 void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
800 {
801 NlaStrip *cs, *csn;
802
803 /* sanity check */
804 if (ELEM(NULL, strips, strip)) {
805 return;
806 }
807
808 /* move each one of the meta-strip's children before the meta-strip
809 * in the list of strips after unlinking them from the meta-strip
810 */
811 for (cs = strip->strips.first; cs; cs = csn) {
812 csn = cs->next;
813 BLI_remlink(&strip->strips, cs);
814 BLI_insertlinkbefore(strips, strip, cs);
815 }
816
817 /* free the meta-strip now */
818 BKE_nlastrip_free(strips, strip, true);
819 }
820
821 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
822 * sel: only consider selected meta-strips, otherwise all meta-strips are removed
823 * onlyTemp: only remove the 'temporary' meta-strips used for transforms
824 */
BKE_nlastrips_clear_metas(ListBase * strips,bool only_sel,bool only_temp)825 void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
826 {
827 NlaStrip *strip, *stripn;
828
829 /* sanity checks */
830 if (ELEM(NULL, strips, strips->first)) {
831 return;
832 }
833
834 /* remove meta-strips fitting the criteria of the arguments */
835 for (strip = strips->first; strip; strip = stripn) {
836 stripn = strip->next;
837
838 /* check if strip is a meta-strip */
839 if (strip->type == NLASTRIP_TYPE_META) {
840 /* if check if selection and 'temporary-only' considerations are met */
841 if ((!only_sel) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
842 if ((!only_temp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
843 BKE_nlastrips_clear_metastrip(strips, strip);
844 }
845 }
846 }
847 }
848 }
849
850 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the
851 * strip isn't attached to any list of strips
852 */
BKE_nlameta_add_strip(NlaStrip * mstrip,NlaStrip * strip)853 bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
854 {
855 /* sanity checks */
856 if (ELEM(NULL, mstrip, strip)) {
857 return false;
858 }
859
860 /* firstly, check if the meta-strip has space for this */
861 if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0) {
862 return false;
863 }
864
865 /* check if this would need to be added to the ends of the meta,
866 * and subsequently, if the neighboring strips allow us enough room
867 */
868 if (strip->start < mstrip->start) {
869 /* check if strip to the left (if it exists) ends before the
870 * start of the strip we're trying to add
871 */
872 if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
873 /* add strip to start of meta's list, and expand dimensions */
874 BLI_addhead(&mstrip->strips, strip);
875 mstrip->start = strip->start;
876
877 return true;
878 }
879 /* failed... no room before */
880 return false;
881 }
882 if (strip->end > mstrip->end) {
883 /* check if strip to the right (if it exists) starts before the
884 * end of the strip we're trying to add
885 */
886 if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
887 /* add strip to end of meta's list, and expand dimensions */
888 BLI_addtail(&mstrip->strips, strip);
889 mstrip->end = strip->end;
890
891 return true;
892 }
893 /* failed... no room after */
894 return false;
895 }
896
897 /* just try to add to the meta-strip (no dimension changes needed) */
898 return BKE_nlastrips_add_strip(&mstrip->strips, strip);
899 }
900
901 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
902 * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
903 */
BKE_nlameta_flush_transforms(NlaStrip * mstrip)904 void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
905 {
906 NlaStrip *strip;
907 float oStart, oEnd, offset;
908 float oLen, nLen;
909 short scaleChanged = 0;
910
911 /* sanity checks
912 * - strip must exist
913 * - strip must be a meta-strip with some contents
914 */
915 if (ELEM(NULL, mstrip, mstrip->strips.first)) {
916 return;
917 }
918 if (mstrip->type != NLASTRIP_TYPE_META) {
919 return;
920 }
921
922 /* get the original start/end points, and calculate the start-frame offset
923 * - these are simply the start/end frames of the child strips,
924 * since we assume they weren't transformed yet
925 */
926 oStart = ((NlaStrip *)mstrip->strips.first)->start;
927 oEnd = ((NlaStrip *)mstrip->strips.last)->end;
928 offset = mstrip->start - oStart;
929
930 /* optimization:
931 * don't flush if nothing changed yet
932 * TODO: maybe we need a flag to say always flush?
933 */
934 if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end)) {
935 return;
936 }
937
938 /* check if scale changed */
939 oLen = oEnd - oStart;
940 nLen = mstrip->end - mstrip->start;
941 if (IS_EQF(nLen, oLen) == 0) {
942 scaleChanged = 1;
943 }
944
945 /* for each child-strip, calculate new start/end points based on this new info */
946 for (strip = mstrip->strips.first; strip; strip = strip->next) {
947 if (scaleChanged) {
948 float p1, p2;
949
950 /* compute positions of endpoints relative to old extents of strip */
951 p1 = (strip->start - oStart) / oLen;
952 p2 = (strip->end - oStart) / oLen;
953
954 /* Apply new strip endpoints using the proportions,
955 * then wait for second pass to flush scale properly. */
956 strip->start = (p1 * nLen) + mstrip->start;
957 strip->end = (p2 * nLen) + mstrip->start;
958 }
959 else {
960 /* just apply the changes in offset to both ends of the strip */
961 strip->start += offset;
962 strip->end += offset;
963 }
964 }
965
966 /* apply a second pass over child strips, to finish up unfinished business */
967 for (strip = mstrip->strips.first; strip; strip = strip->next) {
968 /* only if scale changed, need to perform RNA updates */
969 if (scaleChanged) {
970 PointerRNA ptr;
971
972 /* use RNA updates to compute scale properly */
973 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
974
975 RNA_float_set(&ptr, "frame_start", strip->start);
976 RNA_float_set(&ptr, "frame_end", strip->end);
977 }
978
979 /* finally, make sure the strip's children (if it is a meta-itself), get updated */
980 BKE_nlameta_flush_transforms(strip);
981 }
982 }
983
984 /* NLA-Tracks ---------------------------------------- */
985
986 /* Find the active NLA-track for the given stack */
BKE_nlatrack_find_active(ListBase * tracks)987 NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
988 {
989 NlaTrack *nlt;
990
991 /* sanity check */
992 if (ELEM(NULL, tracks, tracks->first)) {
993 return NULL;
994 }
995
996 /* try to find the first active track */
997 for (nlt = tracks->first; nlt; nlt = nlt->next) {
998 if (nlt->flag & NLATRACK_ACTIVE) {
999 return nlt;
1000 }
1001 }
1002
1003 /* none found */
1004 return NULL;
1005 }
1006
1007 /* Get the NLA Track that the active action/action strip comes from,
1008 * since this info is not stored in AnimData. It also isn't as simple
1009 * as just using the active track, since multiple tracks may have been
1010 * entered at the same time.
1011 */
BKE_nlatrack_find_tweaked(AnimData * adt)1012 NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
1013 {
1014 NlaTrack *nlt;
1015
1016 /* sanity check */
1017 if (adt == NULL) {
1018 return NULL;
1019 }
1020
1021 /* Since the track itself gets disabled, we want the first disabled... */
1022 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1023 if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
1024 /* For good measure, make sure that strip actually exists there */
1025 if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
1026 return nlt;
1027 }
1028 if (G.debug & G_DEBUG) {
1029 printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
1030 __func__,
1031 adt->actstrip,
1032 (adt->actstrip) ? adt->actstrip->name : "<None>",
1033 nlt,
1034 nlt->name);
1035 }
1036 }
1037 }
1038
1039 /* Not found! */
1040 return NULL;
1041 }
1042
1043 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
1044 * that has this status in its AnimData block.
1045 */
BKE_nlatrack_solo_toggle(AnimData * adt,NlaTrack * nlt)1046 void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
1047 {
1048 NlaTrack *nt;
1049
1050 /* sanity check */
1051 if (ELEM(NULL, adt, adt->nla_tracks.first)) {
1052 return;
1053 }
1054
1055 /* firstly, make sure 'solo' flag for all tracks is disabled */
1056 for (nt = adt->nla_tracks.first; nt; nt = nt->next) {
1057 if (nt != nlt) {
1058 nt->flag &= ~NLATRACK_SOLO;
1059 }
1060 }
1061
1062 /* now, enable 'solo' for the given track if appropriate */
1063 if (nlt) {
1064 /* toggle solo status */
1065 nlt->flag ^= NLATRACK_SOLO;
1066
1067 /* set or clear solo-status on AnimData */
1068 if (nlt->flag & NLATRACK_SOLO) {
1069 adt->flag |= ADT_NLA_SOLO_TRACK;
1070 }
1071 else {
1072 adt->flag &= ~ADT_NLA_SOLO_TRACK;
1073 }
1074 }
1075 else {
1076 adt->flag &= ~ADT_NLA_SOLO_TRACK;
1077 }
1078 }
1079
1080 /* Make the given NLA-track the active one for the given stack. If no track is provided,
1081 * this function can be used to simply deactivate all the NLA tracks in the given stack too.
1082 */
BKE_nlatrack_set_active(ListBase * tracks,NlaTrack * nlt_a)1083 void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
1084 {
1085 NlaTrack *nlt;
1086
1087 /* sanity check */
1088 if (ELEM(NULL, tracks, tracks->first)) {
1089 return;
1090 }
1091
1092 /* deactivate all the rest */
1093 for (nlt = tracks->first; nlt; nlt = nlt->next) {
1094 nlt->flag &= ~NLATRACK_ACTIVE;
1095 }
1096
1097 /* set the given one as the active one */
1098 if (nlt_a) {
1099 nlt_a->flag |= NLATRACK_ACTIVE;
1100 }
1101 }
1102
1103 /* Check if there is any space in the given track to add a strip of the given length */
BKE_nlatrack_has_space(NlaTrack * nlt,float start,float end)1104 bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
1105 {
1106 /* sanity checks
1107 * - track must exist
1108 * - track must be editable
1109 * - bounds cannot be equal (0-length is nasty)
1110 */
1111 if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end)) {
1112 return false;
1113 }
1114
1115 if (start > end) {
1116 puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
1117 SWAP(float, start, end);
1118 }
1119
1120 /* check if there's any space left in the track for a strip of the given length */
1121 return BKE_nlastrips_has_space(&nlt->strips, start, end);
1122 }
1123
1124 /* Rearrange the strips in the track so that they are always in order
1125 * (usually only needed after a strip has been moved)
1126 */
BKE_nlatrack_sort_strips(NlaTrack * nlt)1127 void BKE_nlatrack_sort_strips(NlaTrack *nlt)
1128 {
1129 /* sanity checks */
1130 if (ELEM(NULL, nlt, nlt->strips.first)) {
1131 return;
1132 }
1133
1134 /* sort the strips with a more generic function */
1135 BKE_nlastrips_sort_strips(&nlt->strips);
1136 }
1137
1138 /* Add the given NLA-Strip to the given NLA-Track, assuming that it
1139 * isn't currently attached to another one
1140 */
BKE_nlatrack_add_strip(NlaTrack * nlt,NlaStrip * strip)1141 bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip)
1142 {
1143 /* sanity checks */
1144 if (ELEM(NULL, nlt, strip)) {
1145 return false;
1146 }
1147
1148 /* do not allow adding strips if this track is locked */
1149 if (nlt->flag & NLATRACK_PROTECTED) {
1150 return false;
1151 }
1152
1153 /* try to add the strip to the track using a more generic function */
1154 return BKE_nlastrips_add_strip(&nlt->strips, strip);
1155 }
1156
1157 /* Get the extents of the given NLA-Track including gaps between strips,
1158 * returning whether this succeeded or not
1159 */
BKE_nlatrack_get_bounds(NlaTrack * nlt,float bounds[2])1160 bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
1161 {
1162 NlaStrip *strip;
1163
1164 /* initialize bounds */
1165 if (bounds) {
1166 bounds[0] = bounds[1] = 0.0f;
1167 }
1168 else {
1169 return false;
1170 }
1171
1172 /* sanity checks */
1173 if (ELEM(NULL, nlt, nlt->strips.first)) {
1174 return false;
1175 }
1176
1177 /* lower bound is first strip's start frame */
1178 strip = nlt->strips.first;
1179 bounds[0] = strip->start;
1180
1181 /* upper bound is last strip's end frame */
1182 strip = nlt->strips.last;
1183 bounds[1] = strip->end;
1184
1185 /* done */
1186 return true;
1187 }
1188
1189 /* NLA Strips -------------------------------------- */
1190
1191 /* Find the active NLA-strip within the given track */
BKE_nlastrip_find_active(NlaTrack * nlt)1192 NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
1193 {
1194 NlaStrip *strip;
1195
1196 /* sanity check */
1197 if (ELEM(NULL, nlt, nlt->strips.first)) {
1198 return NULL;
1199 }
1200
1201 /* try to find the first active strip */
1202 for (strip = nlt->strips.first; strip; strip = strip->next) {
1203 if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
1204 return strip;
1205 }
1206 }
1207
1208 /* none found */
1209 return NULL;
1210 }
1211
1212 /* Make the given NLA-Strip the active one within the given block */
BKE_nlastrip_set_active(AnimData * adt,NlaStrip * strip)1213 void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
1214 {
1215 NlaTrack *nlt;
1216 NlaStrip *nls;
1217
1218 /* sanity checks */
1219 if (adt == NULL) {
1220 return;
1221 }
1222
1223 /* loop over tracks, deactivating*/
1224 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1225 for (nls = nlt->strips.first; nls; nls = nls->next) {
1226 if (nls != strip) {
1227 nls->flag &= ~NLASTRIP_FLAG_ACTIVE;
1228 }
1229 else {
1230 nls->flag |= NLASTRIP_FLAG_ACTIVE;
1231 }
1232 }
1233 }
1234 }
1235
1236 /* Does the given NLA-strip fall within the given bounds (times)? */
BKE_nlastrip_within_bounds(NlaStrip * strip,float min,float max)1237 bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
1238 {
1239 const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
1240 const float boundsLen = fabsf(max - min);
1241
1242 /* sanity checks */
1243 if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f)) {
1244 return false;
1245 }
1246
1247 /* only ok if at least part of the strip is within the bounding window
1248 * - first 2 cases cover when the strip length is less than the bounding area
1249 * - second 2 cases cover when the strip length is greater than the bounding area
1250 */
1251 if ((stripLen < boundsLen) &&
1252 !(IN_RANGE(strip->start, min, max) || IN_RANGE(strip->end, min, max))) {
1253 return false;
1254 }
1255 if ((stripLen > boundsLen) &&
1256 !(IN_RANGE(min, strip->start, strip->end) || IN_RANGE(max, strip->start, strip->end))) {
1257 return false;
1258 }
1259
1260 /* should be ok! */
1261 return true;
1262 }
1263
1264 /* Ensure that strip doesn't overlap those around it after resizing
1265 * by offsetting those which follow. */
nlastrip_fix_resize_overlaps(NlaStrip * strip)1266 static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
1267 {
1268 /* next strips - do this first, since we're often just getting longer */
1269 if (strip->next) {
1270 NlaStrip *nls = strip->next;
1271 float offset = 0.0f;
1272
1273 if (nls->type == NLASTRIP_TYPE_TRANSITION) {
1274 /* transition strips should grow/shrink to accommodate the resized strip,
1275 * but if the strip's bounds now exceed the transition, we're forced to
1276 * offset everything to maintain the balance
1277 */
1278 if (strip->end <= nls->start) {
1279 /* grow the transition to fill the void */
1280 nls->start = strip->end;
1281 }
1282 else if (strip->end < nls->end) {
1283 /* shrink the transition to give the strip room */
1284 nls->start = strip->end;
1285 }
1286 else {
1287 /* Shrink transition down to 1 frame long (so that it can still be found),
1288 * then offset everything else by the remaining deficit to give the strip room. */
1289 nls->start = nls->end - 1.0f;
1290
1291 /* XXX: review whether preventing fractional values is good here... */
1292 offset = ceilf(strip->end - nls->start);
1293
1294 /* apply necessary offset to ensure that the strip has enough space */
1295 for (; nls; nls = nls->next) {
1296 nls->start += offset;
1297 nls->end += offset;
1298 }
1299 }
1300 }
1301 else if (strip->end > nls->start) {
1302 /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
1303 * otherwise it will be very hard to get rid of later
1304 */
1305 offset = ceilf(strip->end - nls->start);
1306
1307 /* apply to times of all strips in this direction */
1308 for (; nls; nls = nls->next) {
1309 nls->start += offset;
1310 nls->end += offset;
1311 }
1312 }
1313 }
1314
1315 /* previous strips - same routine as before */
1316 /* NOTE: when strip bounds are recalculated, this is not considered! */
1317 if (strip->prev) {
1318 NlaStrip *nls = strip->prev;
1319 float offset = 0.0f;
1320
1321 if (nls->type == NLASTRIP_TYPE_TRANSITION) {
1322 /* transition strips should grow/shrink to accommodate the resized strip,
1323 * but if the strip's bounds now exceed the transition, we're forced to
1324 * offset everything to maintain the balance
1325 */
1326 if (strip->start >= nls->end) {
1327 /* grow the transition to fill the void */
1328 nls->end = strip->start;
1329 }
1330 else if (strip->start > nls->start) {
1331 /* shrink the transition to give the strip room */
1332 nls->end = strip->start;
1333 }
1334 else {
1335 /* Shrink transition down to 1 frame long (so that it can still be found),
1336 * then offset everything else by the remaining deficit to give the strip room. */
1337 nls->end = nls->start + 1.0f;
1338
1339 /* XXX: review whether preventing fractional values is good here... */
1340 offset = ceilf(nls->end - strip->start);
1341
1342 /* apply necessary offset to ensure that the strip has enough space */
1343 for (; nls; nls = nls->prev) {
1344 nls->start -= offset;
1345 nls->end -= offset;
1346 }
1347 }
1348 }
1349 else if (strip->start < nls->end) {
1350 /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
1351 * otherwise it will be very hard to get rid of later
1352 */
1353 offset = ceilf(nls->end - strip->start);
1354
1355 /* apply to times of all strips in this direction */
1356 for (; nls; nls = nls->prev) {
1357 nls->start -= offset;
1358 nls->end -= offset;
1359 }
1360 }
1361 }
1362 }
1363
1364 /** Recalculate the start and end frames for the strip to match the bounds of its action such that
1365 * the overall NLA animation result is unchanged. */
BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip * strip)1366 void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
1367 {
1368 float prev_actstart;
1369
1370 if (strip == NULL || strip->type != NLASTRIP_TYPE_CLIP) {
1371 return;
1372 }
1373
1374 prev_actstart = strip->actstart;
1375
1376 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
1377
1378 /* Set start such that key's do not visually move, to preserve the overall animation result. */
1379 strip->start += (strip->actstart - prev_actstart) * strip->scale;
1380
1381 BKE_nlastrip_recalculate_bounds(strip);
1382 }
1383 /* Recalculate the start and end frames for the current strip, after changing
1384 * the extents of the action or the mapping (repeats or scale factor) info
1385 */
BKE_nlastrip_recalculate_bounds(NlaStrip * strip)1386 void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
1387 {
1388 float actlen, mapping;
1389
1390 /* sanity checks
1391 * - must have a strip
1392 * - can only be done for action clips
1393 */
1394 if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP)) {
1395 return;
1396 }
1397
1398 /* calculate new length factors */
1399 actlen = strip->actend - strip->actstart;
1400 if (IS_EQF(actlen, 0.0f)) {
1401 actlen = 1.0f;
1402 }
1403
1404 mapping = strip->scale * strip->repeat;
1405
1406 /* adjust endpoint of strip in response to this */
1407 if (IS_EQF(mapping, 0.0f) == 0) {
1408 strip->end = (actlen * mapping) + strip->start;
1409 }
1410
1411 /* make sure we don't overlap our neighbors */
1412 nlastrip_fix_resize_overlaps(strip);
1413 }
1414
1415 /* Is the given NLA-strip the first one to occur for the given AnimData block */
1416 // TODO: make this an api method if necessary, but need to add prefix first
nlastrip_is_first(AnimData * adt,NlaStrip * strip)1417 static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
1418 {
1419 NlaTrack *nlt;
1420 NlaStrip *ns;
1421
1422 /* sanity checks */
1423 if (ELEM(NULL, adt, strip)) {
1424 return false;
1425 }
1426
1427 /* check if strip has any strips before it */
1428 if (strip->prev) {
1429 return false;
1430 }
1431
1432 /* check other tracks to see if they have a strip that's earlier */
1433 /* TODO: or should we check that the strip's track is also the first? */
1434 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1435 /* only check the first strip, assuming that they're all in order */
1436 ns = nlt->strips.first;
1437 if (ns) {
1438 if (ns->start < strip->start) {
1439 return false;
1440 }
1441 }
1442 }
1443
1444 /* should be first now */
1445 return true;
1446 }
1447
1448 /* Animated Strips ------------------------------------------- */
1449
1450 /* Check if the given NLA-Track has any strips with own F-Curves */
BKE_nlatrack_has_animated_strips(NlaTrack * nlt)1451 bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
1452 {
1453 NlaStrip *strip;
1454
1455 /* sanity checks */
1456 if (ELEM(NULL, nlt, nlt->strips.first)) {
1457 return false;
1458 }
1459
1460 /* check each strip for F-Curves only (don't care about whether the flags are set) */
1461 for (strip = nlt->strips.first; strip; strip = strip->next) {
1462 if (strip->fcurves.first) {
1463 return true;
1464 }
1465 }
1466
1467 /* none found */
1468 return false;
1469 }
1470
1471 /* Check if given NLA-Tracks have any strips with own F-Curves */
BKE_nlatracks_have_animated_strips(ListBase * tracks)1472 bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
1473 {
1474 NlaTrack *nlt;
1475
1476 /* sanity checks */
1477 if (ELEM(NULL, tracks, tracks->first)) {
1478 return false;
1479 }
1480
1481 /* check each track, stopping on the first hit */
1482 for (nlt = tracks->first; nlt; nlt = nlt->next) {
1483 if (BKE_nlatrack_has_animated_strips(nlt)) {
1484 return true;
1485 }
1486 }
1487
1488 /* none found */
1489 return false;
1490 }
1491
1492 /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
BKE_nlastrip_validate_fcurves(NlaStrip * strip)1493 void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
1494 {
1495 FCurve *fcu;
1496
1497 /* sanity checks */
1498 if (strip == NULL) {
1499 return;
1500 }
1501
1502 /* if controlling influence... */
1503 if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
1504 /* try to get F-Curve */
1505 fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
1506
1507 /* add one if not found */
1508 if (fcu == NULL) {
1509 /* make new F-Curve */
1510 fcu = BKE_fcurve_create();
1511 BLI_addtail(&strip->fcurves, fcu);
1512
1513 /* set default flags */
1514 fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
1515 fcu->auto_smoothing = U.auto_smoothing_new;
1516
1517 /* store path - make copy, and store that */
1518 fcu->rna_path = BLI_strdupn("influence", 9);
1519
1520 /* insert keyframe to ensure current value stays on first refresh */
1521 fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt");
1522 fcu->totvert = 1;
1523
1524 fcu->bezt->vec[1][0] = strip->start;
1525 fcu->bezt->vec[1][1] = strip->influence;
1526
1527 /* Respect User Preferences for default interpolation and handles. */
1528 fcu->bezt->h1 = fcu->bezt->h2 = U.keyhandles_new;
1529 fcu->bezt->ipo = U.ipo_new;
1530 }
1531 }
1532
1533 /* if controlling time... */
1534 if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
1535 /* try to get F-Curve */
1536 fcu = BKE_fcurve_find(&strip->fcurves, "strip_time", 0);
1537
1538 /* add one if not found */
1539 if (fcu == NULL) {
1540 /* make new F-Curve */
1541 fcu = BKE_fcurve_create();
1542 BLI_addtail(&strip->fcurves, fcu);
1543
1544 /* set default flags */
1545 fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
1546 fcu->auto_smoothing = U.auto_smoothing_new;
1547
1548 /* store path - make copy, and store that */
1549 fcu->rna_path = BLI_strdupn("strip_time", 10);
1550
1551 /* TODO: insert a few keyframes to ensure default behavior? */
1552 }
1553 }
1554 }
1555
1556 /* Check if the given RNA pointer + property combo should be handled by
1557 * NLA strip curves or not.
1558 */
BKE_nlastrip_has_curves_for_property(const PointerRNA * ptr,const PropertyRNA * prop)1559 bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
1560 {
1561 /* sanity checks */
1562 if (ELEM(NULL, ptr, prop)) {
1563 return false;
1564 }
1565
1566 /* 1) Must be NLA strip */
1567 if (ptr->type == &RNA_NlaStrip) {
1568 /* 2) Must be one of the predefined properties */
1569 static PropertyRNA *prop_influence = NULL;
1570 static PropertyRNA *prop_time = NULL;
1571 static bool needs_init = true;
1572
1573 /* Init the properties on first use */
1574 if (needs_init) {
1575 prop_influence = RNA_struct_type_find_property(&RNA_NlaStrip, "influence");
1576 prop_time = RNA_struct_type_find_property(&RNA_NlaStrip, "strip_time");
1577
1578 needs_init = false;
1579 }
1580
1581 /* Check if match */
1582 if (ELEM(prop, prop_influence, prop_time)) {
1583 return true;
1584 }
1585 }
1586
1587 /* No criteria met */
1588 return false;
1589 }
1590
1591 /* Sanity Validation ------------------------------------ */
1592
nla_editbone_name_check(void * arg,const char * name)1593 static bool nla_editbone_name_check(void *arg, const char *name)
1594 {
1595 return BLI_ghash_haskey((GHash *)arg, (const void *)name);
1596 }
1597
1598 /* Find (and set) a unique name for a strip from the whole AnimData block
1599 * Uses a similar method to the BLI method, but is implemented differently
1600 * as we need to ensure that the name is unique over several lists of tracks,
1601 * not just a single track.
1602 */
BKE_nlastrip_validate_name(AnimData * adt,NlaStrip * strip)1603 void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
1604 {
1605 GHash *gh;
1606 NlaStrip *tstrip;
1607 NlaTrack *nlt;
1608
1609 /* sanity checks */
1610 if (ELEM(NULL, adt, strip)) {
1611 return;
1612 }
1613
1614 /* give strip a default name if none already */
1615 if (strip->name[0] == 0) {
1616 switch (strip->type) {
1617 case NLASTRIP_TYPE_CLIP: /* act-clip */
1618 BLI_strncpy(strip->name,
1619 (strip->act) ? (strip->act->id.name + 2) : ("<No Action>"),
1620 sizeof(strip->name));
1621 break;
1622 case NLASTRIP_TYPE_TRANSITION: /* transition */
1623 BLI_strncpy(strip->name, "Transition", sizeof(strip->name));
1624 break;
1625 case NLASTRIP_TYPE_META: /* meta */
1626 BLI_strncpy(strip->name, "Meta", sizeof(strip->name));
1627 break;
1628 default:
1629 BLI_strncpy(strip->name, "NLA Strip", sizeof(strip->name));
1630 break;
1631 }
1632 }
1633
1634 /* build a hash-table of all the strips in the tracks
1635 * - this is easier than iterating over all the tracks+strips hierarchy every time
1636 * (and probably faster)
1637 */
1638 gh = BLI_ghash_str_new("nlastrip_validate_name gh");
1639
1640 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1641 for (tstrip = nlt->strips.first; tstrip; tstrip = tstrip->next) {
1642 /* don't add the strip of interest */
1643 if (tstrip == strip) {
1644 continue;
1645 }
1646
1647 /* Use the name of the strip as the key, and the strip as the value,
1648 * since we're mostly interested in the keys. */
1649 BLI_ghash_insert(gh, tstrip->name, tstrip);
1650 }
1651 }
1652
1653 /* If the hash-table has a match for this name, try other names...
1654 * - In an extreme case, it might not be able to find a name,
1655 * but then everything else in Blender would fail too :).
1656 */
1657 BLI_uniquename_cb(nla_editbone_name_check,
1658 (void *)gh,
1659 DATA_("NlaStrip"),
1660 '.',
1661 strip->name,
1662 sizeof(strip->name));
1663
1664 /* free the hash... */
1665 BLI_ghash_free(gh, NULL, NULL);
1666 }
1667
1668 /* ---- */
1669
1670 /* Get strips which overlap the given one at the start/end of its range
1671 * - strip: strip that we're finding overlaps for
1672 * - track: nla-track that the overlapping strips should be found from
1673 * - start, end: frames for the offending endpoints
1674 */
nlastrip_get_endpoint_overlaps(NlaStrip * strip,NlaTrack * track,float ** start,float ** end)1675 static void nlastrip_get_endpoint_overlaps(NlaStrip *strip,
1676 NlaTrack *track,
1677 float **start,
1678 float **end)
1679 {
1680 NlaStrip *nls;
1681
1682 /* find strips that overlap over the start/end of the given strip,
1683 * but which don't cover the entire length
1684 */
1685 /* TODO: this scheme could get quite slow for doing this on many strips... */
1686 for (nls = track->strips.first; nls; nls = nls->next) {
1687 /* Check if strip overlaps (extends over or exactly on)
1688 * the entire range of the strip we're validating. */
1689 if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
1690 *start = NULL;
1691 *end = NULL;
1692 return;
1693 }
1694
1695 /* check if strip doesn't even occur anywhere near... */
1696 if (nls->end < strip->start) {
1697 continue; /* skip checking this strip... not worthy of mention */
1698 }
1699 if (nls->start > strip->end) {
1700 return; /* the range we're after has already passed */
1701 }
1702
1703 /* if this strip is not part of an island of continuous strips, it can be used
1704 * - this check needs to be done for each end of the strip we try and use...
1705 */
1706 if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0) {
1707 if ((nls->end > strip->start) && (nls->end < strip->end)) {
1708 *start = &nls->end;
1709 }
1710 }
1711 if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0) {
1712 if ((nls->start < strip->end) && (nls->start > strip->start)) {
1713 *end = &nls->start;
1714 }
1715 }
1716 }
1717 }
1718
1719 /* Determine auto-blending for the given strip */
BKE_nlastrip_validate_autoblends(NlaTrack * nlt,NlaStrip * nls)1720 static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
1721 {
1722 float *ps = NULL, *pe = NULL;
1723 float *ns = NULL, *ne = NULL;
1724
1725 /* sanity checks */
1726 if (ELEM(NULL, nls, nlt)) {
1727 return;
1728 }
1729 if ((nlt->prev == NULL) && (nlt->next == NULL)) {
1730 return;
1731 }
1732 if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS) == 0) {
1733 return;
1734 }
1735
1736 /* get test ranges */
1737 if (nlt->prev) {
1738 nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
1739 }
1740 if (nlt->next) {
1741 nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
1742 }
1743
1744 /* set overlaps for this strip
1745 * - don't use the values obtained though if the end in question
1746 * is directly followed/preceded by another strip, forming an
1747 * 'island' of continuous strips
1748 */
1749 if ((ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0)) {
1750 /* start overlaps - pick the largest overlap */
1751 if (((ps && ns) && (*ps > *ns)) || (ps)) {
1752 nls->blendin = *ps - nls->start;
1753 }
1754 else {
1755 nls->blendin = *ns - nls->start;
1756 }
1757 }
1758 else { /* no overlap allowed/needed */
1759 nls->blendin = 0.0f;
1760 }
1761
1762 if ((pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0)) {
1763 /* end overlaps - pick the largest overlap */
1764 if (((pe && ne) && (*pe > *ne)) || (pe)) {
1765 nls->blendout = nls->end - *pe;
1766 }
1767 else {
1768 nls->blendout = nls->end - *ne;
1769 }
1770 }
1771 else { /* no overlap allowed/needed */
1772 nls->blendout = 0.0f;
1773 }
1774 }
1775
1776 /* Ensure that auto-blending and other settings are set correctly */
BKE_nla_validate_state(AnimData * adt)1777 void BKE_nla_validate_state(AnimData *adt)
1778 {
1779 NlaStrip *strip, *fstrip = NULL;
1780 NlaTrack *nlt;
1781
1782 /* sanity checks */
1783 if (ELEM(NULL, adt, adt->nla_tracks.first)) {
1784 return;
1785 }
1786
1787 /* Adjust blending values for auto-blending,
1788 * and also do an initial pass to find the earliest strip. */
1789 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1790 for (strip = nlt->strips.first; strip; strip = strip->next) {
1791 /* auto-blending first */
1792 BKE_nlastrip_validate_autoblends(nlt, strip);
1793
1794 /* extend mode - find first strip */
1795 if ((fstrip == NULL) || (strip->start < fstrip->start)) {
1796 fstrip = strip;
1797 }
1798 }
1799 }
1800
1801 /* second pass over the strips to adjust the extend-mode to fix any problems */
1802 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1803 for (strip = nlt->strips.first; strip; strip = strip->next) {
1804 /* apart from 'nothing' option which user has to explicitly choose, we don't really know if
1805 * we should be overwriting the extend setting (but assume that's what the user wanted)
1806 */
1807 /* TODO: 1 solution is to tie this in with auto-blending... */
1808 if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
1809 /* 1) First strip must be set to extend hold, otherwise, stuff before acts dodgy
1810 * 2) Only overwrite extend mode if *not* changing it will most probably result in
1811 * occlusion problems, which will occur if...
1812 * - blendmode = REPLACE
1813 * - all channels the same (this is fiddly to test, so is currently assumed)
1814 *
1815 * Should fix problems such as T29869.
1816 */
1817 if (strip == fstrip) {
1818 strip->extendmode = NLASTRIP_EXTEND_HOLD;
1819 }
1820 else if (strip->blendmode == NLASTRIP_MODE_REPLACE) {
1821 strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
1822 }
1823 }
1824 }
1825 }
1826 }
1827
1828 /* Action Stashing -------------------------------------- */
1829
1830 /* name of stashed tracks - the translation stuff is included here to save extra work */
1831 #define STASH_TRACK_NAME DATA_("[Action Stash]")
1832
1833 /* Check if an action is "stashed" in the NLA already
1834 *
1835 * The criteria for this are:
1836 * 1) The action in question lives in a "stash" track
1837 * 2) We only check first-level strips. That is, we will not check inside meta strips.
1838 */
BKE_nla_action_is_stashed(AnimData * adt,bAction * act)1839 bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
1840 {
1841 NlaTrack *nlt;
1842 NlaStrip *strip;
1843
1844 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1845 if (strstr(nlt->name, STASH_TRACK_NAME)) {
1846 for (strip = nlt->strips.first; strip; strip = strip->next) {
1847 if (strip->act == act) {
1848 return true;
1849 }
1850 }
1851 }
1852 }
1853
1854 return false;
1855 }
1856
1857 /* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
1858 * to retain it in the file for future uses
1859 */
BKE_nla_action_stash(AnimData * adt)1860 bool BKE_nla_action_stash(AnimData *adt)
1861 {
1862 NlaTrack *prev_track = NULL;
1863 NlaTrack *nlt;
1864 NlaStrip *strip;
1865
1866 /* sanity check */
1867 if (ELEM(NULL, adt, adt->action)) {
1868 CLOG_ERROR(&LOG, "Invalid argument - %p %p", adt, adt->action);
1869 return false;
1870 }
1871
1872 /* do not add if it is already stashed */
1873 if (BKE_nla_action_is_stashed(adt, adt->action)) {
1874 return false;
1875 }
1876
1877 /* create a new track, and add this immediately above the previous stashing track */
1878 for (prev_track = adt->nla_tracks.last; prev_track; prev_track = prev_track->prev) {
1879 if (strstr(prev_track->name, STASH_TRACK_NAME)) {
1880 break;
1881 }
1882 }
1883
1884 nlt = BKE_nlatrack_add(adt, prev_track);
1885 BLI_assert(nlt != NULL);
1886
1887 /* We need to ensure that if there wasn't any previous instance,
1888 * it must go to be bottom of the stack. */
1889 if (prev_track == NULL) {
1890 BLI_remlink(&adt->nla_tracks, nlt);
1891 BLI_addhead(&adt->nla_tracks, nlt);
1892 }
1893
1894 BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
1895 BLI_uniquename(
1896 &adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
1897
1898 /* add the action as a strip in this new track
1899 * NOTE: a new user is created here
1900 */
1901 strip = BKE_nlastrip_new(adt->action);
1902 BLI_assert(strip != NULL);
1903
1904 BKE_nlatrack_add_strip(nlt, strip);
1905 BKE_nlastrip_validate_name(adt, strip);
1906
1907 /* mark the stash track and strip so that they doesn't disturb the stack animation,
1908 * and are unlikely to draw attention to itself (or be accidentally bumped around)
1909 *
1910 * NOTE: this must be done *after* adding the strip to the track, or else
1911 * the strip locking will prevent the strip from getting added
1912 */
1913 nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
1914 strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
1915
1916 /* also mark the strip for auto syncing the length, so that the strips accurately
1917 * reflect the length of the action
1918 * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
1919 */
1920 strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
1921
1922 /* succeeded */
1923 return true;
1924 }
1925
1926 /* Core Tools ------------------------------------------- */
1927
1928 /* For the given AnimData block, add the active action to the NLA
1929 * stack (i.e. 'push-down' action). The UI should only allow this
1930 * for normal editing only (i.e. not in editmode for some strip's action),
1931 * so no checks for this are performed.
1932 */
1933 /* TODO: maybe we should have checks for this too... */
BKE_nla_action_pushdown(AnimData * adt)1934 void BKE_nla_action_pushdown(AnimData *adt)
1935 {
1936 NlaStrip *strip;
1937 const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
1938
1939 /* sanity checks */
1940 /* TODO: need to report the error for this */
1941 if (ELEM(NULL, adt, adt->action)) {
1942 return;
1943 }
1944
1945 /* if the action is empty, we also shouldn't try to add to stack,
1946 * as that will cause us grief down the track
1947 */
1948 /* TODO: what about modifiers? */
1949 if (action_has_motion(adt->action) == 0) {
1950 CLOG_ERROR(&LOG, "action has no data");
1951 return;
1952 }
1953
1954 /* add a new NLA strip to the track, which references the active action */
1955 strip = BKE_nlastack_add_strip(adt, adt->action);
1956 if (strip == NULL) {
1957 return;
1958 }
1959
1960 /* clear reference to action now that we've pushed it onto the stack */
1961 id_us_min(&adt->action->id);
1962 adt->action = NULL;
1963
1964 /* copy current "action blending" settings from adt to the strip,
1965 * as it was keyframed with these settings, so omitting them will
1966 * change the effect [T54233]
1967 *
1968 * NOTE: We only do this when there are no tracks
1969 */
1970 if (is_first == false) {
1971 strip->blendmode = adt->act_blendmode;
1972 strip->influence = adt->act_influence;
1973 strip->extendmode = adt->act_extendmode;
1974
1975 if (adt->act_influence < 1.0f) {
1976 /* enable "user-controlled" influence (which will insert a default keyframe)
1977 * so that the influence doesn't get lost on the new update
1978 *
1979 * NOTE: An alternative way would have been to instead hack the influence
1980 * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
1981 * is disabled but auto-blending isn't being used. However, that approach
1982 * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
1983 * so it's better to just do it this way.
1984 */
1985 strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
1986 BKE_nlastrip_validate_fcurves(strip);
1987 }
1988 }
1989
1990 /* if the strip is the first one in the track it lives in, check if there
1991 * are strips in any other tracks that may be before this, and set the extend
1992 * mode accordingly
1993 */
1994 if (nlastrip_is_first(adt, strip) == 0) {
1995 /* Not first, so extend mode can only be:
1996 * NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
1997 * so that it doesn't override strips in previous tracks. */
1998 /* FIXME: this needs to be more automated, since user can rearrange strips */
1999 if (strip->extendmode == NLASTRIP_EXTEND_HOLD) {
2000 strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
2001 }
2002 }
2003
2004 /* make strip the active one... */
2005 BKE_nlastrip_set_active(adt, strip);
2006 }
2007
2008 /* Find the active strip + track combo, and set them up as the tweaking track,
2009 * and return if successful or not.
2010 */
BKE_nla_tweakmode_enter(AnimData * adt)2011 bool BKE_nla_tweakmode_enter(AnimData *adt)
2012 {
2013 NlaTrack *nlt, *activeTrack = NULL;
2014 NlaStrip *strip, *activeStrip = NULL;
2015
2016 /* verify that data is valid */
2017 if (ELEM(NULL, adt, adt->nla_tracks.first)) {
2018 return false;
2019 }
2020
2021 /* if block is already in tweakmode, just leave, but we should report
2022 * that this block is in tweakmode (as our returncode)
2023 */
2024 if (adt->flag & ADT_NLA_EDIT_ON) {
2025 return true;
2026 }
2027
2028 /* go over the tracks, finding the active one, and its active strip
2029 * - if we cannot find both, then there's nothing to do
2030 */
2031 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2032 /* check if active */
2033 if (nlt->flag & NLATRACK_ACTIVE) {
2034 /* store reference to this active track */
2035 activeTrack = nlt;
2036
2037 /* now try to find active strip */
2038 activeStrip = BKE_nlastrip_find_active(nlt);
2039 break;
2040 }
2041 }
2042
2043 /* There are situations where we may have multiple strips selected and we want to enter tweakmode
2044 * on all of those at once. Usually in those cases,
2045 * it will usually just be a single strip per AnimData.
2046 * In such cases, compromise and take the last selected track and/or last selected strip, T28468.
2047 */
2048 if (activeTrack == NULL) {
2049 /* try last selected track for active strip */
2050 for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
2051 if (nlt->flag & NLATRACK_SELECTED) {
2052 /* assume this is the active track */
2053 activeTrack = nlt;
2054
2055 /* try to find active strip */
2056 activeStrip = BKE_nlastrip_find_active(nlt);
2057 break;
2058 }
2059 }
2060 }
2061 if ((activeTrack) && (activeStrip == NULL)) {
2062 /* No active strip in active or last selected track;
2063 * compromise for first selected (assuming only single). */
2064 for (strip = activeTrack->strips.first; strip; strip = strip->next) {
2065 if (strip->flag & (NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE)) {
2066 activeStrip = strip;
2067 break;
2068 }
2069 }
2070 }
2071
2072 if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
2073 if (G.debug & G_DEBUG) {
2074 printf("NLA tweakmode enter - neither active requirement found\n");
2075 printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip);
2076 }
2077 return false;
2078 }
2079
2080 /* Go over all the tracks, tagging each strip that uses the same
2081 * action as the active strip, but leaving everything else alone.
2082 */
2083 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2084 for (strip = nlt->strips.first; strip; strip = strip->next) {
2085 if (strip->act == activeStrip->act) {
2086 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
2087 }
2088 else {
2089 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2090 }
2091 }
2092 }
2093
2094 /* Untag tweaked track. This leads to non tweaked actions being drawn differently than the
2095 * tweaked action. */
2096 activeStrip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2097
2098 /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
2099 * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
2100 */
2101 for (nlt = activeTrack; nlt; nlt = nlt->next) {
2102 nlt->flag |= NLATRACK_DISABLED;
2103 }
2104
2105 /* handle AnimData level changes:
2106 * - 'real' active action to temp storage (no need to change user-counts).
2107 * - Action of active strip set to be the 'active action', and have its usercount incremented.
2108 * - Editing-flag for this AnimData block should also get turned on
2109 * (for more efficient restoring).
2110 * - Take note of the active strip for mapping-correction of keyframes
2111 * in the action being edited.
2112 */
2113 adt->tmpact = adt->action;
2114 adt->action = activeStrip->act;
2115 adt->act_track = activeTrack;
2116 adt->actstrip = activeStrip;
2117 id_us_plus(&activeStrip->act->id);
2118 adt->flag |= ADT_NLA_EDIT_ON;
2119
2120 /* done! */
2121 return true;
2122 }
2123
2124 /* Exit tweakmode for this AnimData block */
BKE_nla_tweakmode_exit(AnimData * adt)2125 void BKE_nla_tweakmode_exit(AnimData *adt)
2126 {
2127 NlaStrip *strip;
2128 NlaTrack *nlt;
2129
2130 /* verify that data is valid */
2131 if (ELEM(NULL, adt, adt->nla_tracks.first)) {
2132 return;
2133 }
2134
2135 /* hopefully the flag is correct - skip if not on */
2136 if ((adt->flag & ADT_NLA_EDIT_ON) == 0) {
2137 return;
2138 }
2139
2140 /* sync the length of the user-strip with the new state of the action
2141 * but only if the user has explicitly asked for this to happen
2142 * (see T34645 for things to be careful about)
2143 */
2144 if ((adt->actstrip) && (adt->actstrip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
2145 strip = adt->actstrip;
2146
2147 /* must be action-clip only (transitions don't have scale) */
2148 if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) {
2149 BKE_nlastrip_recalculate_bounds_sync_action(strip);
2150 }
2151 }
2152
2153 /* for all Tracks, clear the 'disabled' flag
2154 * for all Strips, clear the 'tweak-user' flag
2155 */
2156 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2157 nlt->flag &= ~NLATRACK_DISABLED;
2158
2159 for (strip = nlt->strips.first; strip; strip = strip->next) {
2160 /* sync strip extents if this strip uses the same action */
2161 if ((adt->actstrip) && (adt->actstrip->act == strip->act) &&
2162 (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
2163 BKE_nlastrip_recalculate_bounds_sync_action(strip);
2164 }
2165
2166 /* clear tweakuser flag */
2167 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
2168 }
2169 }
2170
2171 /* handle AnimData level changes:
2172 * - 'temporary' active action needs its usercount decreased, since we're removing this reference
2173 * - 'real' active action is restored from storage
2174 * - storage pointer gets cleared (to avoid having bad notes hanging around)
2175 * - editing-flag for this AnimData block should also get turned off
2176 * - clear pointer to active strip
2177 */
2178 if (adt->action) {
2179 id_us_min(&adt->action->id);
2180 }
2181 adt->action = adt->tmpact;
2182 adt->tmpact = NULL;
2183 adt->act_track = NULL;
2184 adt->actstrip = NULL;
2185 adt->flag &= ~ADT_NLA_EDIT_ON;
2186 }
2187
blend_write_nla_strips(BlendWriter * writer,ListBase * strips)2188 static void blend_write_nla_strips(BlendWriter *writer, ListBase *strips)
2189 {
2190 BLO_write_struct_list(writer, NlaStrip, strips);
2191 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
2192 /* write the strip's F-Curves and modifiers */
2193 BKE_fcurve_blend_write(writer, &strip->fcurves);
2194 BKE_fmodifiers_blend_write(writer, &strip->modifiers);
2195
2196 /* write the strip's children */
2197 blend_write_nla_strips(writer, &strip->strips);
2198 }
2199 }
2200
blend_data_read_nla_strips(BlendDataReader * reader,ListBase * strips)2201 static void blend_data_read_nla_strips(BlendDataReader *reader, ListBase *strips)
2202 {
2203 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
2204 /* strip's child strips */
2205 BLO_read_list(reader, &strip->strips);
2206 blend_data_read_nla_strips(reader, &strip->strips);
2207
2208 /* strip's F-Curves */
2209 BLO_read_list(reader, &strip->fcurves);
2210 BKE_fcurve_blend_read_data(reader, &strip->fcurves);
2211
2212 /* strip's F-Modifiers */
2213 BLO_read_list(reader, &strip->modifiers);
2214 BKE_fmodifiers_blend_read_data(reader, &strip->modifiers, NULL);
2215 }
2216 }
2217
blend_lib_read_nla_strips(BlendLibReader * reader,ID * id,ListBase * strips)2218 static void blend_lib_read_nla_strips(BlendLibReader *reader, ID *id, ListBase *strips)
2219 {
2220 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
2221 /* check strip's children */
2222 blend_lib_read_nla_strips(reader, id, &strip->strips);
2223
2224 /* check strip's F-Curves */
2225 BKE_fcurve_blend_read_lib(reader, id, &strip->fcurves);
2226
2227 /* reassign the counted-reference to action */
2228 BLO_read_id_address(reader, id->lib, &strip->act);
2229 }
2230 }
2231
blend_read_expand_nla_strips(BlendExpander * expander,ListBase * strips)2232 static void blend_read_expand_nla_strips(BlendExpander *expander, ListBase *strips)
2233 {
2234 LISTBASE_FOREACH (NlaStrip *, strip, strips) {
2235 /* check child strips */
2236 blend_read_expand_nla_strips(expander, &strip->strips);
2237
2238 /* check F-Curves */
2239 BKE_fcurve_blend_read_expand(expander, &strip->fcurves);
2240
2241 /* check F-Modifiers */
2242 BKE_fmodifiers_blend_read_expand(expander, &strip->modifiers);
2243
2244 /* relink referenced action */
2245 BLO_expand(expander, strip->act);
2246 }
2247 }
2248
BKE_nla_blend_write(BlendWriter * writer,ListBase * tracks)2249 void BKE_nla_blend_write(BlendWriter *writer, ListBase *tracks)
2250 {
2251 /* write all the tracks */
2252 LISTBASE_FOREACH (NlaTrack *, nlt, tracks) {
2253 /* write the track first */
2254 BLO_write_struct(writer, NlaTrack, nlt);
2255
2256 /* write the track's strips */
2257 blend_write_nla_strips(writer, &nlt->strips);
2258 }
2259 }
2260
BKE_nla_blend_read_data(BlendDataReader * reader,ListBase * tracks)2261 void BKE_nla_blend_read_data(BlendDataReader *reader, ListBase *tracks)
2262 {
2263 LISTBASE_FOREACH (NlaTrack *, nlt, tracks) {
2264 /* relink list of strips */
2265 BLO_read_list(reader, &nlt->strips);
2266
2267 /* relink strip data */
2268 blend_data_read_nla_strips(reader, &nlt->strips);
2269 }
2270 }
2271
BKE_nla_blend_read_lib(BlendLibReader * reader,ID * id,ListBase * tracks)2272 void BKE_nla_blend_read_lib(BlendLibReader *reader, ID *id, ListBase *tracks)
2273 {
2274 /* we only care about the NLA strips inside the tracks */
2275 LISTBASE_FOREACH (NlaTrack *, nlt, tracks) {
2276 blend_lib_read_nla_strips(reader, id, &nlt->strips);
2277 }
2278 }
2279
BKE_nla_blend_read_expand(struct BlendExpander * expander,struct ListBase * tracks)2280 void BKE_nla_blend_read_expand(struct BlendExpander *expander, struct ListBase *tracks)
2281 {
2282 /* nla-data - referenced actions */
2283 LISTBASE_FOREACH (NlaTrack *, nlt, tracks) {
2284 blend_read_expand_nla_strips(expander, &nlt->strips);
2285 }
2286 }
2287