NLA SoC: Recoded the strip<->global time conversion code
[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 // TODO: with things like transitions, should these get freed too? Maybe better as a UI tool
70 void free_nlastrip (ListBase *strips, NlaStrip *strip)
71 {
72         FModifier *fcm, *fmn;
73         
74         /* sanity checks */
75         if (strip == NULL)
76                 return;
77                 
78         /* remove reference to action */
79         if (strip->act)
80                 strip->act->id.us--;
81                 
82         /* free remapping info */
83         //if (strip->remap)
84         //      BKE_animremap_free();
85         
86         /* free own F-Curves */
87         free_fcurves(&strip->fcurves);
88         
89         /* free F-Modifiers */
90         for (fcm= strip->modifiers.first; fcm; fcm= fmn) {
91                 fmn= fcm->next;
92                 
93                 BLI_remlink(&strip->modifiers, fcm);
94                 fcurve_remove_modifier(NULL, fcm);
95         }
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         
156         /* sanity check */
157         if (strip == NULL)
158                 return NULL;
159                 
160         /* make a copy */
161         strip_d= MEM_dupallocN(strip);
162         strip_d->next= strip_d->prev= NULL;
163         
164         /* increase user-count of action */
165         if (strip_d->act)
166                 strip_d->act->id.us++;
167                 
168         /* copy F-Curves and modifiers */
169         copy_fcurves(&strip_d->fcurves, &strip->fcurves);
170         fcurve_copy_modifiers(&strip_d->modifiers, &strip->modifiers);
171         
172         /* return the strip */
173         return strip_d;
174 }
175
176 /* Copy NLA Track */
177 NlaTrack *copy_nlatrack (NlaTrack *nlt)
178 {
179         NlaStrip *strip, *strip_d;
180         NlaTrack *nlt_d;
181         
182         /* sanity check */
183         if (nlt == NULL)
184                 return NULL;
185                 
186         /* make a copy */
187         nlt_d= MEM_dupallocN(nlt);
188         nlt_d->next= nlt_d->prev= NULL;
189         
190         /* make a copy of all the strips, one at a time */
191         nlt_d->strips.first= nlt_d->strips.last= NULL;
192         
193         for (strip= nlt->strips.first; strip; strip= strip->next) {
194                 strip_d= copy_nlastrip(strip);
195                 BLI_addtail(&nlt_d->strips, strip_d);
196         }
197         
198         /* return the copy */
199         return nlt_d;
200 }
201
202 /* Copy all NLA data */
203 void copy_nladata (ListBase *dst, ListBase *src)
204 {
205         NlaTrack *nlt, *nlt_d;
206         
207         /* sanity checks */
208         if ELEM(NULL, dst, src)
209                 return;
210                 
211         /* copy each NLA-track, one at a time */
212         for (nlt= src->first; nlt; nlt= nlt->next) {
213                 /* make a copy, and add the copy to the destination list */
214                 nlt_d= copy_nlatrack(nlt);
215                 BLI_addtail(dst, nlt_d);
216         }
217 }
218
219 /* Adding ------------------------------------------- */
220
221 /* Add a NLA Track to the given AnimData 
222  *      - prev: NLA-Track to add the new one after
223  */
224 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
225 {
226         NlaTrack *nlt;
227         
228         /* sanity checks */
229         if (adt == NULL)
230                 return NULL;
231                 
232         /* allocate new track */
233         nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
234         
235         /* set settings requiring the track to not be part of the stack yet */
236         nlt->flag = NLATRACK_SELECTED;
237         nlt->index= BLI_countlist(&adt->nla_tracks);
238         
239         /* add track to stack, and make it the active one */
240         if (prev)
241                 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
242         else
243                 BLI_addtail(&adt->nla_tracks, nlt);
244         BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
245         
246         /* must have unique name, but we need to seed this */
247         sprintf(nlt->name, "NlaTrack");
248         BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64);
249         
250         /* return the new track */
251         return nlt;
252 }
253
254 /* Add a NLA Strip referencing the given Action */
255 NlaStrip *add_nlastrip (bAction *act)
256 {
257         NlaStrip *strip;
258         
259         /* sanity checks */
260         if (act == NULL)
261                 return NULL;
262                 
263         /* allocate new strip */
264         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
265         
266         /* generic settings 
267          *      - selected flag to highlight this to the user
268          *      - auto-blends to ensure that blend in/out values are automatically 
269          *        determined by overlaps of strips
270          *      - (XXX) synchronisation of strip-length in accordance with changes to action-length
271          *        is not done though, since this should only really happens in editmode for strips now
272          *        though this decision is still subject to further review...
273          */
274         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
275         
276         /* assign the action reference */
277         strip->act= act;
278         id_us_plus(&act->id);
279         
280         /* determine initial range 
281          *      - strip length cannot be 0... ever...
282          */
283         calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
284         
285         strip->start = strip->actstart;
286         strip->end = (IS_EQ(strip->actstart, strip->actend)) ?  (strip->actstart + 1.0f): (strip->actend);
287         
288         /* strip should be referenced as-is */
289         strip->scale= 1.0f;
290         strip->repeat = 1.0f;
291         
292         /* return the new strip */
293         return strip;
294 }
295
296 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
297 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
298 {
299         NlaStrip *strip;
300         NlaTrack *nlt;
301         
302         /* sanity checks */
303         if ELEM(NULL, adt, act)
304                 return NULL;
305         
306         /* create a new NLA strip */
307         strip= add_nlastrip(act);
308         if (strip == NULL)
309                 return NULL;
310         
311         /* firstly try adding strip to last track, but if that fails, add to a new track */
312         if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
313                 /* trying to add to the last track failed (no track or no space), 
314                  * so add a new track to the stack, and add to that...
315                  */
316                 nlt= add_nlatrack(adt, NULL);
317                 BKE_nlatrack_add_strip(nlt, strip);
318         }
319         
320         /* returns the strip added */
321         return strip;
322 }
323
324 /* *************************************************** */
325 /* NLA Evaluation <-> Editing Stuff */
326
327 /* Strip Mapping ------------------------------------- */
328
329 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
330  *      invert = convert action-strip time to global time 
331  */
332 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short invert)
333 {
334         float actlength, repeat, scale;
335         
336         /* get number of repeats */
337         if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f;
338         repeat = strip->repeat;
339         
340         /* scaling */
341         if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f;
342         scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
343         
344         /* length of referenced action */
345         actlength = strip->actend - strip->actstart;
346         if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
347         
348         /* reversed = play strip backwards */
349         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
350                 /* invert = convert action-strip time to global time */
351                 if (invert)
352                         return scale*(strip->actend - cframe) + strip->start; // FIXME: this doesn't work for multiple repeats yet
353                 else {
354                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
355                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
356                                  * by catching the case where repeats is a whole number, which means that the end of the strip
357                                  * could also be interpreted as the end of the start of a repeat
358                                  */
359                                 return strip->actstart;
360                         }
361                         else {
362                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
363                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
364                                  */
365                                 return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; 
366                         }
367                 }
368         }
369         else {
370                 /* invert = convert action-strip time to global time */
371                 if (invert)
372                         return scale*(cframe - strip->actstart) + strip->start; // FIXME: this doesn't work for mutiple repeats yet
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->actend;
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->actstart + fmod(cframe - strip->start, actlength*scale) / scale; 
386                         }
387                 }
388         }
389 }
390
391 /* non clipped mapping for strip-time <-> global time (for Transitions)
392  *      invert = convert action-strip time to global time 
393  */
394 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short invert)
395 {
396         float length;
397         
398         /* length of strip */
399         length= strip->end - strip->start;
400         
401         /* reversed = play strip backwards */
402         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
403                 /* invert = convert within-strip-time to global time */
404                 if (invert)
405                         return strip->end - (length * cframe);
406                 else
407                         return (strip->end - cframe) / length;
408         }
409         else {
410                 /* invert = convert within-strip-time to global time */
411                 if (invert)
412                         return (length * cframe) + strip->start;
413                 else
414                         return (cframe - strip->start) / length;
415         }
416 }
417
418 /* non clipped mapping for strip-time <-> global time
419  *      invert = convert action-strip time to global time 
420  *
421  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
422  * but should not be directly relied on for stuff which interacts with editors
423  */
424 float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
425 {
426         switch (strip->type) {
427                 case NLASTRIP_TYPE_TRANSITION: /* transition */
428                         return nlastrip_get_frame_transition(strip, cframe, invert);
429                 
430                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
431                 default:
432                         return nlastrip_get_frame_actionclip(strip, cframe, invert);
433         }       
434 }
435
436
437 /* Non clipped mapping for strip-time <-> global time
438  *      invert = convert strip-time to global time 
439  *
440  * Public API method - perform this mapping using the given AnimData block
441  * and perform any necessary sanity checks on the value
442  */
443 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short invert)
444 {
445         NlaStrip *strip;
446         
447         /* sanity checks 
448          *      - obviously we've got to have some starting data
449          *      - when not in tweakmode, the active Action does not have any scaling applied :)
450          */
451         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0)
452                 return cframe;
453                 
454         /* if the active-strip info has been stored already, access this, otherwise look this up
455          * and store for (very probable) future usage
456          */
457         if (adt->actstrip == NULL) {
458                 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
459                 adt->actstrip= BKE_nlastrip_find_active(nlt);
460         }
461         strip= adt->actstrip;
462         
463         /* sanity checks 
464          *      - in rare cases, we may not be able to find this strip for some reason (internal error)
465          *      - for now, if the user has defined a curve to control the time, this correction cannot be performed
466          *        reliably...
467          */
468         if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
469                 return cframe;
470                 
471         /* perform the correction now... */
472         return nlastrip_get_frame(strip, cframe, invert);
473 }
474
475 /* *************************************************** */
476 /* Basic Utilities */
477
478 /* NLA-Tracks ---------------------------------------- */
479
480 /* Find the active NLA-track for the given stack */
481 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
482 {
483         NlaTrack *nlt;
484         
485         /* sanity check */
486         if ELEM(NULL, tracks, tracks->first)
487                 return NULL;
488                 
489         /* try to find the first active track */
490         for (nlt= tracks->first; nlt; nlt= nlt->next) {
491                 if (nlt->flag & NLATRACK_ACTIVE)
492                         return nlt;
493         }
494         
495         /* none found */
496         return NULL;
497 }
498
499 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
500  * that has this status in its AnimData block.
501  */
502 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
503 {
504         NlaTrack *nt;
505         
506         /* sanity check */
507         if ELEM(NULL, adt, adt->nla_tracks.first)
508                 return;
509                 
510         /* firstly, make sure 'solo' flag for all tracks is disabled */
511         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
512                 if (nt != nlt)
513                         nt->flag &= ~NLATRACK_SOLO;
514         }
515                 
516         /* now, enable 'solo' for the given track if appropriate */
517         if (nlt) {
518                 /* toggle solo status */
519                 nlt->flag ^= NLATRACK_SOLO;
520                 
521                 /* set or clear solo-status on AnimData */
522                 if (nlt->flag & NLATRACK_SOLO)
523                         adt->flag |= ADT_NLA_SOLO_TRACK;
524                 else
525                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
526         }
527         else
528                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
529 }
530
531 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
532  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
533  */
534 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
535 {
536         NlaTrack *nlt;
537         
538         /* sanity check */
539         if ELEM(NULL, tracks, tracks->first)
540                 return;
541         
542         /* deactive all the rest */
543         for (nlt= tracks->first; nlt; nlt= nlt->next) 
544                 nlt->flag &= ~NLATRACK_ACTIVE;
545                 
546         /* set the given one as the active one */
547         if (nlt_a)
548                 nlt_a->flag |= NLATRACK_ACTIVE;
549 }
550
551 /* Check if there is any space in the last track to add the given strip */
552 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
553 {
554         NlaStrip *strip;
555         
556         /* sanity checks */
557         if ((nlt == NULL) || IS_EQ(start, end))
558                 return 0;
559         if (start > end) {
560                 puts("BKE_nlatrack_has_space error... start and end arguments swapped");
561                 SWAP(float, start, end);
562         }
563         
564         /* loop over NLA strips checking for any overlaps with this area... */
565         for (strip= nlt->strips.first; strip; strip= strip->next) {
566                 /* if start frame of strip is past the target end-frame, that means that
567                  * we've gone past the window we need to check for, so things are fine
568                  */
569                 if (strip->start > end)
570                         return 1;
571                 
572                 /* if the end of the strip is greater than either of the boundaries, the range
573                  * must fall within the extents of the strip
574                  */
575                 if ((strip->end > start) || (strip->end > end))
576                         return 0;
577         }
578         
579         /* if we are still here, we haven't encountered any overlapping strips */
580         return 1;
581 }
582
583 /* Rearrange the strips in the track so that they are always in order 
584  * (usually only needed after a strip has been moved) 
585  */
586 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
587 {
588         ListBase tmp = {NULL, NULL};
589         NlaStrip *strip, *sstrip;
590         
591         /* sanity checks */
592         if ELEM(NULL, nlt, nlt->strips.first)
593                 return;
594                 
595         /* we simply perform insertion sort on this list, since it is assumed that per track,
596          * there are only likely to be at most 5-10 strips
597          */
598         for (strip= nlt->strips.first; strip; strip= strip->next) {
599                 short not_added = 1;
600                 
601                 /* remove this strip from the list, and add it to the new list, searching from the end of 
602                  * the list, assuming that the lists are in order 
603                  */
604                 BLI_remlink(&nlt->strips, strip);
605                 
606                 for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) {
607                         /* check if add after */
608                         if (sstrip->end < strip->start) {
609                                 BLI_insertlinkafter(&tmp, sstrip, strip);
610                                 not_added= 0;
611                                 break;
612                         }
613                 }
614                 
615                 /* add before first? */
616                 if (not_added)
617                         BLI_addhead(&tmp, strip);
618         }
619         
620         /* reassign the start and end points of the strips */
621         nlt->strips.first= tmp.first;
622         nlt->strips.last= tmp.last;
623 }
624
625 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
626  * isn't currently attached to another one 
627  */
628 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
629 {
630         NlaStrip *ns;
631         short not_added = 1;
632         
633         /* sanity checks */
634         if ELEM(NULL, nlt, strip)
635                 return 0;
636                 
637         /* check if any space to add */
638         if (BKE_nlatrack_has_space(nlt, strip->start, strip->end)==0)
639                 return 0;
640         
641         /* find the right place to add the strip to the nominated track */
642         for (ns= nlt->strips.first; ns; ns= ns->next) {
643                 /* if current strip occurs after the new strip, add it before */
644                 if (ns->start > strip->end) {
645                         BLI_insertlinkbefore(&nlt->strips, ns, strip);
646                         not_added= 0;
647                         break;
648                 }
649         }
650         if (not_added) {
651                 /* just add to the end of the list of the strips then... */
652                 BLI_addtail(&nlt->strips, strip);
653         }
654         
655         /* added... */
656         return 1;
657 }
658
659 /* NLA Strips -------------------------------------- */
660
661 /* Find the active NLA-strip within the given track */
662 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
663 {
664         NlaStrip *strip;
665         
666         /* sanity check */
667         if ELEM(NULL, nlt, nlt->strips.first)
668                 return NULL;
669                 
670         /* try to find the first active strip */
671         for (strip= nlt->strips.first; strip; strip= strip->next) {
672                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
673                         return strip;
674         }
675         
676         /* none found */
677         return NULL;
678 }
679
680 /* Does the given NLA-strip fall within the given bounds (times)? */
681 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
682 {
683         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
684         const float boundsLen= (float)fabs(max - min);
685         
686         /* sanity checks */
687         if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
688                 return 0;
689         
690         /* only ok if at least part of the strip is within the bounding window
691          *      - first 2 cases cover when the strip length is less than the bounding area
692          *      - second 2 cases cover when the strip length is greater than the bounding area
693          */
694         if ( (stripLen < boundsLen) && 
695                  !(IN_RANGE(strip->start, min, max) ||
696                    IN_RANGE(strip->end, min, max)) )
697         {
698                 return 0;
699         }
700         if ( (stripLen > boundsLen) && 
701                  !(IN_RANGE(min, strip->start, strip->end) ||
702                    IN_RANGE(max, strip->start, strip->end)) )
703         {
704                 return 0;
705         }
706         
707         /* should be ok! */
708         return 1;
709 }
710
711 /* Is the given NLA-strip the first one to occur for the given AnimData block */
712 // TODO: make this an api method if necesary, but need to add prefix first
713 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
714 {
715         NlaTrack *nlt;
716         NlaStrip *ns;
717         
718         /* sanity checks */
719         if ELEM(NULL, adt, strip)
720                 return 0;
721                 
722         /* check if strip has any strips before it */
723         if (strip->prev)
724                 return 0;
725                 
726         /* check other tracks to see if they have a strip that's earlier */
727         // TODO: or should we check that the strip's track is also the first?
728         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
729                 /* only check the first strip, assuming that they're all in order */
730                 ns= nlt->strips.first;
731                 if (ns) {
732                         if (ns->start < strip->start)
733                                 return 0;
734                 }
735         }       
736         
737         /* should be first now */
738         return 1;
739 }
740  
741 /* Tools ------------------------------------------- */
742
743 /* For the given AnimData block, add the active action to the NLA
744  * stack (i.e. 'push-down' action). The UI should only allow this 
745  * for normal editing only (i.e. not in editmode for some strip's action),
746  * so no checks for this are performed.
747  */
748 // TODO: maybe we should have checks for this too...
749 void BKE_nla_action_pushdown (AnimData *adt)
750 {
751         NlaStrip *strip;
752         
753         /* sanity checks */
754         // TODO: need to report the error for this
755         if ELEM(NULL, adt, adt->action) 
756                 return;
757                 
758         /* if the action is empty, we also shouldn't try to add to stack, 
759          * as that will cause us grief down the track
760          */
761         // TODO: what about modifiers?
762         if (action_has_motion(adt->action) == 0) {
763                 printf("BKE_nla_action_pushdown(): action has no data \n");
764                 return;
765         }
766         
767         /* add a new NLA strip to the track, which references the active action */
768         strip= add_nlastrip_to_stack(adt, adt->action);
769         
770         /* do other necessary work on strip */  
771         if (strip) {
772                 /* clear reference to action now that we've pushed it onto the stack */
773                 adt->action->id.us--;
774                 adt->action= NULL;
775                 
776                 /* if the strip is the first one in the track it lives in, check if there
777                  * are strips in any other tracks that may be before this, and set the extend
778                  * mode accordingly
779                  */
780                 if (nlastrip_is_first(adt, strip) == 0) {
781                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
782                          * so that it doesn't override strips in previous tracks
783                          */
784                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
785                 }
786         }
787 }
788
789
790 /* Find the active strip + track combo, and set them up as the tweaking track,
791  * and return if successful or not.
792  */
793 short BKE_nla_tweakmode_enter (AnimData *adt)
794 {
795         NlaTrack *nlt, *activeTrack=NULL;
796         NlaStrip *strip, *activeStrip=NULL;
797         
798         /* verify that data is valid */
799         if ELEM(NULL, adt, adt->nla_tracks.first)
800                 return 0;
801                 
802         /* if block is already in tweakmode, just leave, but we should report 
803          * that this block is in tweakmode (as our returncode)
804          */
805         if (adt->flag & ADT_NLA_EDIT_ON)
806                 return 1;
807                 
808         /* go over the tracks, finding the active one, and its active strip
809          *      - if we cannot find both, then there's nothing to do
810          */
811         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
812                 /* check if active */
813                 if (nlt->flag & NLATRACK_ACTIVE) {
814                         /* store reference to this active track */
815                         activeTrack= nlt;
816                         
817                         /* now try to find active strip */
818                         activeStrip= BKE_nlastrip_find_active(nlt);
819                         break;
820                 }       
821         }
822         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
823                 printf("NLA tweakmode enter - neither active requirement found \n");
824                 return 0;
825         }
826                 
827         /* go over all the tracks up to the active one, tagging each strip that uses the same 
828          * action as the active strip, but leaving everything else alone
829          */
830         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
831                 for (strip= nlt->strips.first; strip; strip= strip->next) {
832                         if (strip->act == activeStrip->act)
833                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
834                         else
835                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; // XXX probably don't need to clear this...
836                 }
837         }
838         
839         
840         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
841          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
842          */
843         for (nlt= activeTrack; nlt; nlt= nlt->next)
844                 nlt->flag |= NLATRACK_DISABLED;
845         
846         /* handle AnimData level changes:
847          *      - 'real' active action to temp storage (no need to change user-counts)
848          *      - action of active strip set to be the 'active action', and have its usercount incremented
849          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
850          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
851          */
852         adt->tmpact= adt->action;
853         adt->action= activeStrip->act;
854         adt->actstrip= activeStrip;
855         id_us_plus(&activeStrip->act->id);
856         adt->flag |= ADT_NLA_EDIT_ON;
857         
858         /* done! */
859         return 1;
860 }
861
862 /* Exit tweakmode for this AnimData block */
863 void BKE_nla_tweakmode_exit (AnimData *adt)
864 {
865         NlaStrip *strip;
866         NlaTrack *nlt;
867         
868         /* verify that data is valid */
869         if ELEM(NULL, adt, adt->nla_tracks.first)
870                 return;
871                 
872         /* hopefully the flag is correct - skip if not on */
873         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
874                 return;
875                 
876         // TODO: need to sync the user-strip with the new state of the action!
877                 
878         /* for all NLA-tracks, clear the 'disabled' flag
879          * for all NLA-strips, clear the 'tweak-user' flag
880          */
881         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
882                 nlt->flag &= ~NLATRACK_DISABLED;
883                 
884                 for (strip= nlt->strips.first; strip; strip= strip->next) 
885                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
886         }
887         
888         /* handle AnimData level changes:
889          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
890          *      - 'real' active action is restored from storage
891          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
892          *      - editing-flag for this AnimData block should also get turned off
893          *      - clear pointer to active strip
894          */
895         if (adt->action) adt->action->id.us--;
896         adt->action= adt->tmpact;
897         adt->tmpact= NULL;
898         adt->actstrip= NULL;
899         adt->flag &= ~ADT_NLA_EDIT_ON;
900 }
901
902 /* *************************************************** */