NLA SoC: More work on Meta-Strips
[blender.git] / source / blender / blenkernel / intern / nla.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39
40 #include "DNA_anim_types.h"
41 #include "DNA_action_types.h"
42
43 #include "BKE_animsys.h"
44 #include "BKE_action.h"
45 #include "BKE_fcurve.h"
46 #include "BKE_nla.h"
47 #include "BKE_blender.h"
48 #include "BKE_library.h"
49 #include "BKE_object.h"
50 #include "BKE_utildefines.h"
51
52 #include "RNA_access.h"
53 #include "nla_private.h"
54
55
56 #ifdef HAVE_CONFIG_H
57 #include <config.h>
58 #endif
59
60
61 /* *************************************************** */
62 /* Data Management */
63
64 /* Freeing ------------------------------------------- */
65
66 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
67  * and the strip itself. 
68  */
69 void free_nlastrip (ListBase *strips, NlaStrip *strip)
70 {
71         NlaStrip *cs, *csn;
72         
73         /* sanity checks */
74         if (strip == NULL)
75                 return;
76                 
77         /* free child-strips */
78         for (cs= strip->strips.first; cs; cs= csn) {
79                 csn= cs->next;
80                 free_nlastrip(&strip->strips, cs);
81         }
82                 
83         /* remove reference to action */
84         if (strip->act)
85                 strip->act->id.us--;
86                 
87         /* free remapping info */
88         //if (strip->remap)
89         //      BKE_animremap_free();
90         
91         /* free own F-Curves */
92         free_fcurves(&strip->fcurves);
93         
94         /* free own F-Modifiers */
95         free_fmodifiers(&strip->modifiers);
96         
97         /* free the strip itself */
98         if (strips)
99                 BLI_freelinkN(strips, strip);
100         else
101                 MEM_freeN(strip);
102 }
103
104 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
105  * and the track itself.
106  */
107 void free_nlatrack (ListBase *tracks, NlaTrack *nlt)
108 {
109         NlaStrip *strip, *stripn;
110         
111         /* sanity checks */
112         if (nlt == NULL)
113                 return;
114                 
115         /* free strips */
116         for (strip= nlt->strips.first; strip; strip= stripn) {
117                 stripn= strip->next;
118                 free_nlastrip(&nlt->strips, strip);
119         }
120         
121         /* free NLA track itself now */
122         if (tracks)
123                 BLI_freelinkN(tracks, nlt);
124         else
125                 MEM_freeN(nlt);
126 }
127
128 /* Free the elements of type NLA Tracks provided in the given list, but do not free
129  * the list itself since that is not free-standing
130  */
131 void free_nladata (ListBase *tracks)
132 {
133         NlaTrack *nlt, *nltn;
134         
135         /* sanity checks */
136         if ELEM(NULL, tracks, tracks->first)
137                 return;
138                 
139         /* free tracks one by one */
140         for (nlt= tracks->first; nlt; nlt= nltn) {
141                 nltn= nlt->next;
142                 free_nlatrack(tracks, nlt);
143         }
144         
145         /* clear the list's pointers to be safe */
146         tracks->first= tracks->last= NULL;
147 }
148
149 /* Copying ------------------------------------------- */
150
151 /* Copy NLA strip */
152 NlaStrip *copy_nlastrip (NlaStrip *strip)
153 {
154         NlaStrip *strip_d;
155         NlaStrip *cs, *cs_d;
156         
157         /* sanity check */
158         if (strip == NULL)
159                 return NULL;
160                 
161         /* make a copy */
162         strip_d= MEM_dupallocN(strip);
163         strip_d->next= strip_d->prev= NULL;
164         
165         /* increase user-count of action */
166         if (strip_d->act)
167                 strip_d->act->id.us++;
168                 
169         /* copy F-Curves and modifiers */
170         copy_fcurves(&strip_d->fcurves, &strip->fcurves);
171         copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
172         
173         /* make a copy of all the child-strips, one at a time */
174         strip_d->strips.first= strip_d->strips.last= NULL;
175         
176         for (cs= strip->strips.first; cs; cs= cs->next) {
177                 cs_d= copy_nlastrip(cs);
178                 BLI_addtail(&strip_d->strips, cs_d);
179         }
180         
181         /* return the strip */
182         return strip_d;
183 }
184
185 /* Copy NLA Track */
186 NlaTrack *copy_nlatrack (NlaTrack *nlt)
187 {
188         NlaStrip *strip, *strip_d;
189         NlaTrack *nlt_d;
190         
191         /* sanity check */
192         if (nlt == NULL)
193                 return NULL;
194                 
195         /* make a copy */
196         nlt_d= MEM_dupallocN(nlt);
197         nlt_d->next= nlt_d->prev= NULL;
198         
199         /* make a copy of all the strips, one at a time */
200         nlt_d->strips.first= nlt_d->strips.last= NULL;
201         
202         for (strip= nlt->strips.first; strip; strip= strip->next) {
203                 strip_d= copy_nlastrip(strip);
204                 BLI_addtail(&nlt_d->strips, strip_d);
205         }
206         
207         /* return the copy */
208         return nlt_d;
209 }
210
211 /* Copy all NLA data */
212 void copy_nladata (ListBase *dst, ListBase *src)
213 {
214         NlaTrack *nlt, *nlt_d;
215         
216         /* sanity checks */
217         if ELEM(NULL, dst, src)
218                 return;
219                 
220         /* copy each NLA-track, one at a time */
221         for (nlt= src->first; nlt; nlt= nlt->next) {
222                 /* make a copy, and add the copy to the destination list */
223                 nlt_d= copy_nlatrack(nlt);
224                 BLI_addtail(dst, nlt_d);
225         }
226 }
227
228 /* Adding ------------------------------------------- */
229
230 /* Add a NLA Track to the given AnimData 
231  *      - prev: NLA-Track to add the new one after
232  */
233 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
234 {
235         NlaTrack *nlt;
236         
237         /* sanity checks */
238         if (adt == NULL)
239                 return NULL;
240                 
241         /* allocate new track */
242         nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
243         
244         /* set settings requiring the track to not be part of the stack yet */
245         nlt->flag = NLATRACK_SELECTED;
246         nlt->index= BLI_countlist(&adt->nla_tracks);
247         
248         /* add track to stack, and make it the active one */
249         if (prev)
250                 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
251         else
252                 BLI_addtail(&adt->nla_tracks, nlt);
253         BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
254         
255         /* must have unique name, but we need to seed this */
256         sprintf(nlt->name, "NlaTrack");
257         BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64);
258         
259         /* return the new track */
260         return nlt;
261 }
262
263 /* Add a NLA Strip referencing the given Action */
264 NlaStrip *add_nlastrip (bAction *act)
265 {
266         NlaStrip *strip;
267         
268         /* sanity checks */
269         if (act == NULL)
270                 return NULL;
271                 
272         /* allocate new strip */
273         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
274         
275         /* generic settings 
276          *      - selected flag to highlight this to the user
277          *      - auto-blends to ensure that blend in/out values are automatically 
278          *        determined by overlaps of strips
279          *      - (XXX) synchronisation of strip-length in accordance with changes to action-length
280          *        is not done though, since this should only really happens in editmode for strips now
281          *        though this decision is still subject to further review...
282          */
283         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
284         
285         /* assign the action reference */
286         strip->act= act;
287         id_us_plus(&act->id);
288         
289         /* determine initial range 
290          *      - strip length cannot be 0... ever...
291          */
292         calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
293         
294         strip->start = strip->actstart;
295         strip->end = (IS_EQ(strip->actstart, strip->actend)) ?  (strip->actstart + 1.0f): (strip->actend);
296         
297         /* strip should be referenced as-is */
298         strip->scale= 1.0f;
299         strip->repeat = 1.0f;
300         
301         /* return the new strip */
302         return strip;
303 }
304
305 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
306 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
307 {
308         NlaStrip *strip;
309         NlaTrack *nlt;
310         
311         /* sanity checks */
312         if ELEM(NULL, adt, act)
313                 return NULL;
314         
315         /* create a new NLA strip */
316         strip= add_nlastrip(act);
317         if (strip == NULL)
318                 return NULL;
319         
320         /* firstly try adding strip to last track, but if that fails, add to a new track */
321         if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
322                 /* trying to add to the last track failed (no track or no space), 
323                  * so add a new track to the stack, and add to that...
324                  */
325                 nlt= add_nlatrack(adt, NULL);
326                 BKE_nlatrack_add_strip(nlt, strip);
327         }
328         
329         /* returns the strip added */
330         return strip;
331 }
332
333 /* *************************************************** */
334 /* NLA Evaluation <-> Editing Stuff */
335
336 /* Strip Mapping ------------------------------------- */
337
338 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
339  *      invert = convert action-strip time to global time 
340  */
341 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode)
342 {
343         float actlength, repeat, scale;
344         
345         /* get number of repeats */
346         if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f;
347         repeat = strip->repeat;
348         
349         /* scaling */
350         if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f;
351         scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
352         
353         /* length of referenced action */
354         actlength = strip->actend - strip->actstart;
355         if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
356         
357         /* reversed = play strip backwards */
358         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
359                 // FIXME: this won't work right with Graph Editor?
360                 if (mode == NLATIME_CONVERT_MAP) {
361                         return strip->end - scale*(cframe - strip->actstart);
362                 }
363                 else if (mode == NLATIME_CONVERT_UNMAP) {
364                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
365                         
366                         /* this method doesn't clip the values to lie within the action range only 
367                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
368                          *      - the fmod(...) works in the same way as for eval 
369                          */
370                         return strip->actend - (repeatsNum * actlength * scale) 
371                                         - (fmod(cframe - strip->start, actlength*scale) / scale);
372                 }
373                 else {
374                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
375                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
376                                  * by catching the case where repeats is a whole number, which means that the end of the strip
377                                  * could also be interpreted as the end of the start of a repeat
378                                  */
379                                 return strip->actstart;
380                         }
381                         else {
382                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
383                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
384                                  */
385                                 return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; 
386                         }
387                 }
388         }
389         else {
390                 if (mode == NLATIME_CONVERT_MAP) {
391                         return strip->start + scale*(cframe - strip->actstart);
392                 }
393                 else if (mode == NLATIME_CONVERT_UNMAP) {
394                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
395                         
396                         /* this method doesn't clip the values to lie within the action range only 
397                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
398                          *      - the fmod(...) works in the same way as for eval 
399                          */
400                         return strip->actstart + (repeatsNum * actlength * scale) 
401                                         + (fmod(cframe - strip->start, actlength*scale) / scale);
402                 }
403                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
404                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
405                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
406                                  * by catching the case where repeats is a whole number, which means that the end of the strip
407                                  * could also be interpreted as the end of the start of a repeat
408                                  */
409                                 return strip->actend;
410                         }
411                         else {
412                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
413                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
414                                  */
415                                 return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale; 
416                         }
417                 }
418         }
419 }
420
421 /* non clipped mapping for strip-time <-> global time (for Transitions)
422  *      invert = convert action-strip time to global time 
423  */
424 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
425 {
426         float length;
427         
428         /* length of strip */
429         length= strip->end - strip->start;
430         
431         /* reversed = play strip backwards */
432         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
433                 if (mode == NLATIME_CONVERT_MAP)
434                         return strip->end - (length * cframe);
435                 else
436                         return (strip->end - cframe) / length;
437         }
438         else {
439                 if (mode == NLATIME_CONVERT_MAP)
440                         return (length * cframe) + strip->start;
441                 else
442                         return (cframe - strip->start) / length;
443         }
444 }
445
446 /* non clipped mapping for strip-time <-> global time
447  *      mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
448  *
449  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
450  * but should not be directly relied on for stuff which interacts with editors
451  */
452 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
453 {
454         switch (strip->type) {
455                 case NLASTRIP_TYPE_META: /* meta (is just a container for other strips, so shouldn't use the action-clip method) */
456                 case NLASTRIP_TYPE_TRANSITION: /* transition */
457                         return nlastrip_get_frame_transition(strip, cframe, mode);
458                 
459                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
460                 default:
461                         return nlastrip_get_frame_actionclip(strip, cframe, mode);
462         }       
463 }
464
465
466 /* Non clipped mapping for strip-time <-> global time
467  *      mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
468  *
469  * Public API method - perform this mapping using the given AnimData block
470  * and perform any necessary sanity checks on the value
471  */
472 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
473 {
474         NlaStrip *strip;
475         
476         /* sanity checks 
477          *      - obviously we've got to have some starting data
478          *      - when not in tweakmode, the active Action does not have any scaling applied :)
479          *      - when in tweakmode, if the no-mapping flag is set, do not map
480          */
481         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
482                 return cframe;
483                 
484         /* if the active-strip info has been stored already, access this, otherwise look this up
485          * and store for (very probable) future usage
486          */
487         if (adt->actstrip == NULL) {
488                 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
489                 adt->actstrip= BKE_nlastrip_find_active(nlt);
490         }
491         strip= adt->actstrip;
492         
493         /* sanity checks 
494          *      - in rare cases, we may not be able to find this strip for some reason (internal error)
495          *      - for now, if the user has defined a curve to control the time, this correction cannot be performed
496          *        reliably...
497          */
498         if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
499                 return cframe;
500                 
501         /* perform the correction now... */
502         return nlastrip_get_frame(strip, cframe, mode);
503 }
504
505 /* *************************************************** */
506 /* Basic Utilities */
507
508 /* List of Strips ------------------------------------ */
509 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
510
511 /* Check if there is any space in the given list to add the given strip */
512 short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
513 {
514         NlaStrip *strip;
515         
516         /* sanity checks */
517         if ((strips == NULL) || IS_EQ(start, end))
518                 return 0;
519         if (start > end) {
520                 puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
521                 SWAP(float, start, end);
522         }
523         
524         /* loop over NLA strips checking for any overlaps with this area... */
525         for (strip= strips->first; strip; strip= strip->next) {
526                 /* if start frame of strip is past the target end-frame, that means that
527                  * we've gone past the window we need to check for, so things are fine
528                  */
529                 if (strip->start > end)
530                         return 1;
531                 
532                 /* if the end of the strip is greater than either of the boundaries, the range
533                  * must fall within the extents of the strip
534                  */
535                 if ((strip->end > start) || (strip->end > end))
536                         return 0;
537         }
538         
539         /* if we are still here, we haven't encountered any overlapping strips */
540         return 1;
541 }
542
543 /* Rearrange the strips in the track so that they are always in order 
544  * (usually only needed after a strip has been moved) 
545  */
546 void BKE_nlastrips_sort_strips (ListBase *strips)
547 {
548         ListBase tmp = {NULL, NULL};
549         NlaStrip *strip, *sstrip;
550         
551         /* sanity checks */
552         if ELEM(NULL, strips, strips->first)
553                 return;
554                 
555         /* we simply perform insertion sort on this list, since it is assumed that per track,
556          * there are only likely to be at most 5-10 strips
557          */
558         for (strip= strips->first; strip; strip= strip->next) {
559                 short not_added = 1;
560                 
561                 /* remove this strip from the list, and add it to the new list, searching from the end of 
562                  * the list, assuming that the lists are in order 
563                  */
564                 BLI_remlink(strips, strip);
565                 
566                 for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) {
567                         /* check if add after */
568                         if (sstrip->end < strip->start) {
569                                 BLI_insertlinkafter(&tmp, sstrip, strip);
570                                 not_added= 0;
571                                 break;
572                         }
573                 }
574                 
575                 /* add before first? */
576                 if (not_added)
577                         BLI_addhead(&tmp, strip);
578         }
579         
580         /* reassign the start and end points of the strips */
581         strips->first= tmp.first;
582         strips->last= tmp.last;
583 }
584
585 /* Add the given NLA-Strip to the given list of strips, assuming that it 
586  * isn't currently a member of another list
587  */
588 short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
589 {
590         NlaStrip *ns;
591         short not_added = 1;
592         
593         /* sanity checks */
594         if ELEM(NULL, strips, strip)
595                 return 0;
596                 
597         /* check if any space to add */
598         if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0)
599                 return 0;
600         
601         /* find the right place to add the strip to the nominated track */
602         for (ns= strips->first; ns; ns= ns->next) {
603                 /* if current strip occurs after the new strip, add it before */
604                 if (ns->start > strip->end) {
605                         BLI_insertlinkbefore(strips, ns, strip);
606                         not_added= 0;
607                         break;
608                 }
609         }
610         if (not_added) {
611                 /* just add to the end of the list of the strips then... */
612                 BLI_addtail(strips, strip);
613         }
614         
615         /* added... */
616         return 1;
617 }
618
619
620 /* Meta-Strips ------------------------------------ */
621
622 /* Convert 'islands' (i.e. continuous string of) selected strips to be
623  * contained within 'Meta-Strips' which act as strips which contain strips.
624  *      temp: are the meta-strips to be created 'temporary' ones used for transforms?
625  */
626 void BKE_nlastrips_make_metas (ListBase *strips, short temp)
627 {
628         NlaStrip *mstrip = NULL;
629         NlaStrip *strip, *stripn;
630         
631         /* sanity checks */
632         if ELEM(NULL, strips, strips->first)
633                 return;
634         
635         /* group all continuous chains of selected strips into meta-strips */
636         for (strip= strips->first; strip; strip= stripn) {
637                 stripn= strip->next;
638                 
639                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
640                         /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
641                         if (mstrip == NULL) {
642                                 /* add a new meta-strip, and add it before the current strip that it will replace... */
643                                 mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
644                                 mstrip->type = NLASTRIP_TYPE_META;
645                                 BLI_insertlinkbefore(strips, strip, mstrip);
646                                 
647                                 /* set flags */
648                                 mstrip->flag = NLASTRIP_FLAG_SELECT;
649                                 
650                                 /* set temp flag if appropriate (i.e. for transform-type editing) */
651                                 if (temp)
652                                         mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
653                                 
654                                 /* make its start frame be set to the start frame of the current strip */
655                                 mstrip->start= strip->start;
656                         }
657                         
658                         /* remove the selected strips from the track, and add to the meta */
659                         BLI_remlink(strips, strip);
660                         BLI_addtail(&mstrip->strips, strip);
661                         
662                         /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
663                         mstrip->end= strip->end;
664                 }
665                 else {
666                         /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
667                          * so stop adding strips to the current meta
668                          */
669                         mstrip= NULL;
670                 }
671         }
672 }
673
674 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
675  *      sel: only consider selected meta-strips, otherwise all meta-strips are removed
676  *      onlyTemp: only remove the 'temporary' meta-strips used for transforms
677  */
678 void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp)
679 {
680         NlaStrip *strip, *stripn;
681         
682         /* sanity checks */
683         if ELEM(NULL, strips, strips->first)
684                 return;
685         
686         /* remove meta-strips fitting the criteria of the arguments */
687         for (strip= strips->first; strip; strip= stripn) {
688                 stripn= strip->next;
689                 
690                 /* check if strip is a meta-strip */
691                 if (strip->type == NLASTRIP_TYPE_META) {
692                         /* if check if selection and 'temporary-only' considerations are met */
693                         if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
694                                 if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
695                                         NlaStrip *cs, *csn;
696                                         
697                                         /* move each one of the meta-strip's children before the meta-strip
698                                          * in the list of strips after unlinking them from the meta-strip
699                                          */
700                                         for (cs= strip->strips.first; cs; cs= csn) {
701                                                 csn= cs->next;
702                                                 BLI_remlink(&strip->strips, cs);
703                                                 BLI_insertlinkbefore(strips, strip, cs);
704                                         }
705                                         
706                                         /* free the meta-strip now */
707                                         BLI_freelinkN(strips, strip);
708                                 }
709                         }
710                 }
711         }
712 }
713
714 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the
715  * strip isn't attached to anyy list of strips 
716  */
717 short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip)
718 {
719         /* sanity checks */
720         if ELEM(NULL, mstrip, strip)
721                 return 0;
722                 
723         /* firstly, check if the meta-strip has space for this */
724         if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
725                 return 0;
726                 
727         /* check if this would need to be added to the ends of the meta,
728          * and subsequently, if the neighbouring strips allow us enough room
729          */
730         if (strip->start < mstrip->start) {
731                 /* check if strip to the left (if it exists) ends before the 
732                  * start of the strip we're trying to add 
733                  */
734                 if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
735                         /* add strip to start of meta's list, and expand dimensions */
736                         BLI_addhead(&mstrip->strips, strip);
737                         mstrip->start= strip->start;
738                         
739                         return 1;
740                 }
741                 else /* failed... no room before */
742                         return 0;
743         }
744         else if (strip->end > mstrip->end) {
745                 /* check if strip to the right (if it exists) starts before the 
746                  * end of the strip we're trying to add 
747                  */
748                 if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
749                         /* add strip to end of meta's list, and expand dimensions */
750                         BLI_addtail(&mstrip->strips, strip);
751                         mstrip->end= strip->end;
752                         
753                         return 1;
754                 }
755                 else /* failed... no room after */
756                         return 0;
757         }
758         else {
759                 /* just try to add to the meta-strip (no dimension changes needed) */
760                 return BKE_nlastrips_add_strip(&mstrip->strips, strip);
761         }
762 }
763
764 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively), 
765  * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
766  */
767 void BKE_nlameta_flush_transforms (NlaStrip *mstrip) 
768 {
769         NlaStrip *strip;
770         float oStart, oEnd, offset;
771         
772         /* sanity checks 
773          *      - strip must exist
774          *      - strip must be a meta-strip with some contents
775          */
776         if ELEM(NULL, mstrip, mstrip->strips.first)
777                 return;
778         if (mstrip->type != NLASTRIP_TYPE_META)
779                 return;
780                 
781         /* get the original start/end points, and calculate the start-frame offset
782          *      - these are simply the start/end frames of the child strips, 
783          *        since we assume they weren't transformed yet
784          */
785         oStart= ((NlaStrip *)mstrip->strips.first)->start;
786         oEnd= ((NlaStrip *)mstrip->strips.last)->end;
787         offset= mstrip->start - oStart;
788         
789         /* optimisation:
790          * don't flush if nothing changed yet
791          *      TODO: maybe we need a flag to say always flush?
792          */
793         if (IS_EQ(oStart, mstrip->start) && IS_EQ(oEnd, mstrip->end))
794                 return;
795         
796         /* for each child-strip, calculate new start/end points based on this new info */
797         for (strip= mstrip->strips.first; strip; strip= strip->next) {
798                 //PointerRNA strip_ptr;
799                 
800                 /* firstly, just apply the changes in offset to both ends of the strip */
801                 strip->start += offset;
802                 strip->end += offset;
803                 
804                 /* now, we need to fix the endpoint to take into account scaling */
805                 // TODO..
806                 
807                 /* finally, make sure the strip's children (if it is a meta-itself), get updated */
808                 BKE_nlameta_flush_transforms(strip);
809         }
810 }
811
812 /* NLA-Tracks ---------------------------------------- */
813
814 /* Find the active NLA-track for the given stack */
815 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
816 {
817         NlaTrack *nlt;
818         
819         /* sanity check */
820         if ELEM(NULL, tracks, tracks->first)
821                 return NULL;
822                 
823         /* try to find the first active track */
824         for (nlt= tracks->first; nlt; nlt= nlt->next) {
825                 if (nlt->flag & NLATRACK_ACTIVE)
826                         return nlt;
827         }
828         
829         /* none found */
830         return NULL;
831 }
832
833 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
834  * that has this status in its AnimData block.
835  */
836 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
837 {
838         NlaTrack *nt;
839         
840         /* sanity check */
841         if ELEM(NULL, adt, adt->nla_tracks.first)
842                 return;
843                 
844         /* firstly, make sure 'solo' flag for all tracks is disabled */
845         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
846                 if (nt != nlt)
847                         nt->flag &= ~NLATRACK_SOLO;
848         }
849                 
850         /* now, enable 'solo' for the given track if appropriate */
851         if (nlt) {
852                 /* toggle solo status */
853                 nlt->flag ^= NLATRACK_SOLO;
854                 
855                 /* set or clear solo-status on AnimData */
856                 if (nlt->flag & NLATRACK_SOLO)
857                         adt->flag |= ADT_NLA_SOLO_TRACK;
858                 else
859                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
860         }
861         else
862                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
863 }
864
865 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
866  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
867  */
868 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
869 {
870         NlaTrack *nlt;
871         
872         /* sanity check */
873         if ELEM(NULL, tracks, tracks->first)
874                 return;
875         
876         /* deactive all the rest */
877         for (nlt= tracks->first; nlt; nlt= nlt->next) 
878                 nlt->flag &= ~NLATRACK_ACTIVE;
879                 
880         /* set the given one as the active one */
881         if (nlt_a)
882                 nlt_a->flag |= NLATRACK_ACTIVE;
883 }
884
885
886 /* Check if there is any space in the given track to add a strip of the given length */
887 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
888 {
889         /* sanity checks */
890         if ((nlt == NULL) || IS_EQ(start, end))
891                 return 0;
892         if (start > end) {
893                 puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
894                 SWAP(float, start, end);
895         }
896         
897         /* check if there's any space left in the track for a strip of the given length */
898         return BKE_nlastrips_has_space(&nlt->strips, start, end);
899 }
900
901 /* Rearrange the strips in the track so that they are always in order 
902  * (usually only needed after a strip has been moved) 
903  */
904 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
905 {
906         /* sanity checks */
907         if ELEM(NULL, nlt, nlt->strips.first)
908                 return;
909         
910         /* sort the strips with a more generic function */
911         BKE_nlastrips_sort_strips(&nlt->strips);
912 }
913
914 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
915  * isn't currently attached to another one 
916  */
917 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
918 {
919         /* sanity checks */
920         if ELEM(NULL, nlt, strip)
921                 return 0;
922                 
923         /* try to add the strip to the track using a more generic function */
924         return BKE_nlastrips_add_strip(&nlt->strips, strip);
925 }
926
927 /* NLA Strips -------------------------------------- */
928
929 /* Find the active NLA-strip within the given track */
930 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
931 {
932         NlaStrip *strip;
933         
934         /* sanity check */
935         if ELEM(NULL, nlt, nlt->strips.first)
936                 return NULL;
937                 
938         /* try to find the first active strip */
939         for (strip= nlt->strips.first; strip; strip= strip->next) {
940                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
941                         return strip;
942         }
943         
944         /* none found */
945         return NULL;
946 }
947
948 /* Does the given NLA-strip fall within the given bounds (times)? */
949 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
950 {
951         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
952         const float boundsLen= (float)fabs(max - min);
953         
954         /* sanity checks */
955         if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
956                 return 0;
957         
958         /* only ok if at least part of the strip is within the bounding window
959          *      - first 2 cases cover when the strip length is less than the bounding area
960          *      - second 2 cases cover when the strip length is greater than the bounding area
961          */
962         if ( (stripLen < boundsLen) && 
963                  !(IN_RANGE(strip->start, min, max) ||
964                    IN_RANGE(strip->end, min, max)) )
965         {
966                 return 0;
967         }
968         if ( (stripLen > boundsLen) && 
969                  !(IN_RANGE(min, strip->start, strip->end) ||
970                    IN_RANGE(max, strip->start, strip->end)) )
971         {
972                 return 0;
973         }
974         
975         /* should be ok! */
976         return 1;
977 }
978
979 /* Is the given NLA-strip the first one to occur for the given AnimData block */
980 // TODO: make this an api method if necesary, but need to add prefix first
981 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
982 {
983         NlaTrack *nlt;
984         NlaStrip *ns;
985         
986         /* sanity checks */
987         if ELEM(NULL, adt, strip)
988                 return 0;
989                 
990         /* check if strip has any strips before it */
991         if (strip->prev)
992                 return 0;
993                 
994         /* check other tracks to see if they have a strip that's earlier */
995         // TODO: or should we check that the strip's track is also the first?
996         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
997                 /* only check the first strip, assuming that they're all in order */
998                 ns= nlt->strips.first;
999                 if (ns) {
1000                         if (ns->start < strip->start)
1001                                 return 0;
1002                 }
1003         }       
1004         
1005         /* should be first now */
1006         return 1;
1007 }
1008  
1009 /* Tools ------------------------------------------- */
1010
1011 /* For the given AnimData block, add the active action to the NLA
1012  * stack (i.e. 'push-down' action). The UI should only allow this 
1013  * for normal editing only (i.e. not in editmode for some strip's action),
1014  * so no checks for this are performed.
1015  */
1016 // TODO: maybe we should have checks for this too...
1017 void BKE_nla_action_pushdown (AnimData *adt)
1018 {
1019         NlaStrip *strip;
1020         
1021         /* sanity checks */
1022         // TODO: need to report the error for this
1023         if ELEM(NULL, adt, adt->action) 
1024                 return;
1025                 
1026         /* if the action is empty, we also shouldn't try to add to stack, 
1027          * as that will cause us grief down the track
1028          */
1029         // TODO: what about modifiers?
1030         if (action_has_motion(adt->action) == 0) {
1031                 printf("BKE_nla_action_pushdown(): action has no data \n");
1032                 return;
1033         }
1034         
1035         /* add a new NLA strip to the track, which references the active action */
1036         strip= add_nlastrip_to_stack(adt, adt->action);
1037         
1038         /* do other necessary work on strip */  
1039         if (strip) {
1040                 /* clear reference to action now that we've pushed it onto the stack */
1041                 adt->action->id.us--;
1042                 adt->action= NULL;
1043                 
1044                 /* if the strip is the first one in the track it lives in, check if there
1045                  * are strips in any other tracks that may be before this, and set the extend
1046                  * mode accordingly
1047                  */
1048                 if (nlastrip_is_first(adt, strip) == 0) {
1049                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
1050                          * so that it doesn't override strips in previous tracks
1051                          */
1052                         // FIXME: this needs to be more automated, since user can rearrange strips
1053                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
1054                 }
1055         }
1056 }
1057
1058
1059 /* Find the active strip + track combo, and set them up as the tweaking track,
1060  * and return if successful or not.
1061  */
1062 short BKE_nla_tweakmode_enter (AnimData *adt)
1063 {
1064         NlaTrack *nlt, *activeTrack=NULL;
1065         NlaStrip *strip, *activeStrip=NULL;
1066         
1067         /* verify that data is valid */
1068         if ELEM(NULL, adt, adt->nla_tracks.first)
1069                 return 0;
1070                 
1071         /* if block is already in tweakmode, just leave, but we should report 
1072          * that this block is in tweakmode (as our returncode)
1073          */
1074         if (adt->flag & ADT_NLA_EDIT_ON)
1075                 return 1;
1076                 
1077         /* go over the tracks, finding the active one, and its active strip
1078          *      - if we cannot find both, then there's nothing to do
1079          */
1080         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1081                 /* check if active */
1082                 if (nlt->flag & NLATRACK_ACTIVE) {
1083                         /* store reference to this active track */
1084                         activeTrack= nlt;
1085                         
1086                         /* now try to find active strip */
1087                         activeStrip= BKE_nlastrip_find_active(nlt);
1088                         break;
1089                 }       
1090         }
1091         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
1092                 printf("NLA tweakmode enter - neither active requirement found \n");
1093                 return 0;
1094         }
1095                 
1096         /* go over all the tracks up to the active one, tagging each strip that uses the same 
1097          * action as the active strip, but leaving everything else alone
1098          */
1099         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
1100                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1101                         if (strip->act == activeStrip->act)
1102                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
1103                         else
1104                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
1105                 }
1106         }
1107         
1108         
1109         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
1110          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
1111          */
1112         for (nlt= activeTrack; nlt; nlt= nlt->next)
1113                 nlt->flag |= NLATRACK_DISABLED;
1114         
1115         /* handle AnimData level changes:
1116          *      - 'real' active action to temp storage (no need to change user-counts)
1117          *      - action of active strip set to be the 'active action', and have its usercount incremented
1118          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
1119          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
1120          */
1121         adt->tmpact= adt->action;
1122         adt->action= activeStrip->act;
1123         adt->actstrip= activeStrip;
1124         id_us_plus(&activeStrip->act->id);
1125         adt->flag |= ADT_NLA_EDIT_ON;
1126         
1127         /* done! */
1128         return 1;
1129 }
1130
1131 /* Exit tweakmode for this AnimData block */
1132 void BKE_nla_tweakmode_exit (AnimData *adt)
1133 {
1134         NlaStrip *strip;
1135         NlaTrack *nlt;
1136         
1137         /* verify that data is valid */
1138         if ELEM(NULL, adt, adt->nla_tracks.first)
1139                 return;
1140                 
1141         /* hopefully the flag is correct - skip if not on */
1142         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
1143                 return;
1144                 
1145         // TODO: need to sync the user-strip with the new state of the action!
1146                 
1147         /* for all Tracks, clear the 'disabled' flag
1148          * for all Strips, clear the 'tweak-user' flag
1149          */
1150         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1151                 nlt->flag &= ~NLATRACK_DISABLED;
1152                 
1153                 for (strip= nlt->strips.first; strip; strip= strip->next) 
1154                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
1155         }
1156         
1157         /* handle AnimData level changes:
1158          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
1159          *      - 'real' active action is restored from storage
1160          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
1161          *      - editing-flag for this AnimData block should also get turned off
1162          *      - clear pointer to active strip
1163          */
1164         if (adt->action) adt->action->id.us--;
1165         adt->action= adt->tmpact;
1166         adt->tmpact= NULL;
1167         adt->actstrip= NULL;
1168         adt->flag &= ~ADT_NLA_EDIT_ON;
1169 }
1170
1171 /* *************************************************** */