NLA SoC: Start of 'Meta' Strips
[blender-staging.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 /* NLA-Tracks ---------------------------------------- */
620
621 /* Find the active NLA-track for the given stack */
622 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
623 {
624         NlaTrack *nlt;
625         
626         /* sanity check */
627         if ELEM(NULL, tracks, tracks->first)
628                 return NULL;
629                 
630         /* try to find the first active track */
631         for (nlt= tracks->first; nlt; nlt= nlt->next) {
632                 if (nlt->flag & NLATRACK_ACTIVE)
633                         return nlt;
634         }
635         
636         /* none found */
637         return NULL;
638 }
639
640 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
641  * that has this status in its AnimData block.
642  */
643 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
644 {
645         NlaTrack *nt;
646         
647         /* sanity check */
648         if ELEM(NULL, adt, adt->nla_tracks.first)
649                 return;
650                 
651         /* firstly, make sure 'solo' flag for all tracks is disabled */
652         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
653                 if (nt != nlt)
654                         nt->flag &= ~NLATRACK_SOLO;
655         }
656                 
657         /* now, enable 'solo' for the given track if appropriate */
658         if (nlt) {
659                 /* toggle solo status */
660                 nlt->flag ^= NLATRACK_SOLO;
661                 
662                 /* set or clear solo-status on AnimData */
663                 if (nlt->flag & NLATRACK_SOLO)
664                         adt->flag |= ADT_NLA_SOLO_TRACK;
665                 else
666                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
667         }
668         else
669                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
670 }
671
672 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
673  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
674  */
675 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
676 {
677         NlaTrack *nlt;
678         
679         /* sanity check */
680         if ELEM(NULL, tracks, tracks->first)
681                 return;
682         
683         /* deactive all the rest */
684         for (nlt= tracks->first; nlt; nlt= nlt->next) 
685                 nlt->flag &= ~NLATRACK_ACTIVE;
686                 
687         /* set the given one as the active one */
688         if (nlt_a)
689                 nlt_a->flag |= NLATRACK_ACTIVE;
690 }
691
692
693 /* Check if there is any space in the given track to add a strip of the given length */
694 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
695 {
696         /* sanity checks */
697         if ((nlt == NULL) || IS_EQ(start, end))
698                 return 0;
699         if (start > end) {
700                 puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
701                 SWAP(float, start, end);
702         }
703         
704         /* check if there's any space left in the track for a strip of the given length */
705         return BKE_nlastrips_has_space(&nlt->strips, start, end);
706 }
707
708 /* Rearrange the strips in the track so that they are always in order 
709  * (usually only needed after a strip has been moved) 
710  */
711 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
712 {
713         /* sanity checks */
714         if ELEM(NULL, nlt, nlt->strips.first)
715                 return;
716         
717         /* sort the strips with a more generic function */
718         BKE_nlastrips_sort_strips(&nlt->strips);
719 }
720
721 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
722  * isn't currently attached to another one 
723  */
724 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
725 {
726         /* sanity checks */
727         if ELEM(NULL, nlt, strip)
728                 return 0;
729                 
730         /* try to add the strip to the track using a more generic function */
731         return BKE_nlastrips_add_strip(&nlt->strips, strip);
732 }
733
734 /* NLA Strips -------------------------------------- */
735
736 /* Find the active NLA-strip within the given track */
737 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
738 {
739         NlaStrip *strip;
740         
741         /* sanity check */
742         if ELEM(NULL, nlt, nlt->strips.first)
743                 return NULL;
744                 
745         /* try to find the first active strip */
746         for (strip= nlt->strips.first; strip; strip= strip->next) {
747                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
748                         return strip;
749         }
750         
751         /* none found */
752         return NULL;
753 }
754
755 /* Does the given NLA-strip fall within the given bounds (times)? */
756 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
757 {
758         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
759         const float boundsLen= (float)fabs(max - min);
760         
761         /* sanity checks */
762         if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
763                 return 0;
764         
765         /* only ok if at least part of the strip is within the bounding window
766          *      - first 2 cases cover when the strip length is less than the bounding area
767          *      - second 2 cases cover when the strip length is greater than the bounding area
768          */
769         if ( (stripLen < boundsLen) && 
770                  !(IN_RANGE(strip->start, min, max) ||
771                    IN_RANGE(strip->end, min, max)) )
772         {
773                 return 0;
774         }
775         if ( (stripLen > boundsLen) && 
776                  !(IN_RANGE(min, strip->start, strip->end) ||
777                    IN_RANGE(max, strip->start, strip->end)) )
778         {
779                 return 0;
780         }
781         
782         /* should be ok! */
783         return 1;
784 }
785
786 /* Is the given NLA-strip the first one to occur for the given AnimData block */
787 // TODO: make this an api method if necesary, but need to add prefix first
788 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
789 {
790         NlaTrack *nlt;
791         NlaStrip *ns;
792         
793         /* sanity checks */
794         if ELEM(NULL, adt, strip)
795                 return 0;
796                 
797         /* check if strip has any strips before it */
798         if (strip->prev)
799                 return 0;
800                 
801         /* check other tracks to see if they have a strip that's earlier */
802         // TODO: or should we check that the strip's track is also the first?
803         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
804                 /* only check the first strip, assuming that they're all in order */
805                 ns= nlt->strips.first;
806                 if (ns) {
807                         if (ns->start < strip->start)
808                                 return 0;
809                 }
810         }       
811         
812         /* should be first now */
813         return 1;
814 }
815  
816 /* Tools ------------------------------------------- */
817
818 /* For the given AnimData block, add the active action to the NLA
819  * stack (i.e. 'push-down' action). The UI should only allow this 
820  * for normal editing only (i.e. not in editmode for some strip's action),
821  * so no checks for this are performed.
822  */
823 // TODO: maybe we should have checks for this too...
824 void BKE_nla_action_pushdown (AnimData *adt)
825 {
826         NlaStrip *strip;
827         
828         /* sanity checks */
829         // TODO: need to report the error for this
830         if ELEM(NULL, adt, adt->action) 
831                 return;
832                 
833         /* if the action is empty, we also shouldn't try to add to stack, 
834          * as that will cause us grief down the track
835          */
836         // TODO: what about modifiers?
837         if (action_has_motion(adt->action) == 0) {
838                 printf("BKE_nla_action_pushdown(): action has no data \n");
839                 return;
840         }
841         
842         /* add a new NLA strip to the track, which references the active action */
843         strip= add_nlastrip_to_stack(adt, adt->action);
844         
845         /* do other necessary work on strip */  
846         if (strip) {
847                 /* clear reference to action now that we've pushed it onto the stack */
848                 adt->action->id.us--;
849                 adt->action= NULL;
850                 
851                 /* if the strip is the first one in the track it lives in, check if there
852                  * are strips in any other tracks that may be before this, and set the extend
853                  * mode accordingly
854                  */
855                 if (nlastrip_is_first(adt, strip) == 0) {
856                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
857                          * so that it doesn't override strips in previous tracks
858                          */
859                         // FIXME: this needs to be more automated, since user can rearrange strips
860                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
861                 }
862         }
863 }
864
865
866 /* Find the active strip + track combo, and set them up as the tweaking track,
867  * and return if successful or not.
868  */
869 short BKE_nla_tweakmode_enter (AnimData *adt)
870 {
871         NlaTrack *nlt, *activeTrack=NULL;
872         NlaStrip *strip, *activeStrip=NULL;
873         
874         /* verify that data is valid */
875         if ELEM(NULL, adt, adt->nla_tracks.first)
876                 return 0;
877                 
878         /* if block is already in tweakmode, just leave, but we should report 
879          * that this block is in tweakmode (as our returncode)
880          */
881         if (adt->flag & ADT_NLA_EDIT_ON)
882                 return 1;
883                 
884         /* go over the tracks, finding the active one, and its active strip
885          *      - if we cannot find both, then there's nothing to do
886          */
887         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
888                 /* check if active */
889                 if (nlt->flag & NLATRACK_ACTIVE) {
890                         /* store reference to this active track */
891                         activeTrack= nlt;
892                         
893                         /* now try to find active strip */
894                         activeStrip= BKE_nlastrip_find_active(nlt);
895                         break;
896                 }       
897         }
898         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
899                 printf("NLA tweakmode enter - neither active requirement found \n");
900                 return 0;
901         }
902                 
903         /* go over all the tracks up to the active one, tagging each strip that uses the same 
904          * action as the active strip, but leaving everything else alone
905          */
906         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
907                 for (strip= nlt->strips.first; strip; strip= strip->next) {
908                         if (strip->act == activeStrip->act)
909                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
910                         else
911                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
912                 }
913         }
914         
915         
916         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
917          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
918          */
919         for (nlt= activeTrack; nlt; nlt= nlt->next)
920                 nlt->flag |= NLATRACK_DISABLED;
921         
922         /* handle AnimData level changes:
923          *      - 'real' active action to temp storage (no need to change user-counts)
924          *      - action of active strip set to be the 'active action', and have its usercount incremented
925          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
926          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
927          */
928         adt->tmpact= adt->action;
929         adt->action= activeStrip->act;
930         adt->actstrip= activeStrip;
931         id_us_plus(&activeStrip->act->id);
932         adt->flag |= ADT_NLA_EDIT_ON;
933         
934         /* done! */
935         return 1;
936 }
937
938 /* Exit tweakmode for this AnimData block */
939 void BKE_nla_tweakmode_exit (AnimData *adt)
940 {
941         NlaStrip *strip;
942         NlaTrack *nlt;
943         
944         /* verify that data is valid */
945         if ELEM(NULL, adt, adt->nla_tracks.first)
946                 return;
947                 
948         /* hopefully the flag is correct - skip if not on */
949         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
950                 return;
951                 
952         // TODO: need to sync the user-strip with the new state of the action!
953                 
954         /* for all Tracks, clear the 'disabled' flag
955          * for all Strips, clear the 'tweak-user' flag
956          */
957         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
958                 nlt->flag &= ~NLATRACK_DISABLED;
959                 
960                 for (strip= nlt->strips.first; strip; strip= strip->next) 
961                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
962         }
963         
964         /* handle AnimData level changes:
965          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
966          *      - 'real' active action is restored from storage
967          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
968          *      - editing-flag for this AnimData block should also get turned off
969          *      - clear pointer to active strip
970          */
971         if (adt->action) adt->action->id.us--;
972         adt->action= adt->tmpact;
973         adt->tmpact= NULL;
974         adt->actstrip= NULL;
975         adt->flag &= ~ADT_NLA_EDIT_ON;
976 }
977
978 /* *************************************************** */