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