NLA SoC: Separating out F-Modifier API
[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 // 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         /* sanity checks */
73         if (strip == NULL)
74                 return;
75                 
76         /* remove reference to action */
77         if (strip->act)
78                 strip->act->id.us--;
79                 
80         /* free remapping info */
81         //if (strip->remap)
82         //      BKE_animremap_free();
83         
84         /* free own F-Curves */
85         free_fcurves(&strip->fcurves);
86         
87         /* free own F-Modifiers */
88         free_fmodifiers(&strip->modifiers);
89         
90         /* free the strip itself */
91         if (strips)
92                 BLI_freelinkN(strips, strip);
93         else
94                 MEM_freeN(strip);
95 }
96
97 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
98  * and the track itself.
99  */
100 void free_nlatrack (ListBase *tracks, NlaTrack *nlt)
101 {
102         NlaStrip *strip, *stripn;
103         
104         /* sanity checks */
105         if (nlt == NULL)
106                 return;
107                 
108         /* free strips */
109         for (strip= nlt->strips.first; strip; strip= stripn) {
110                 stripn= strip->next;
111                 free_nlastrip(&nlt->strips, strip);
112         }
113         
114         /* free NLA track itself now */
115         if (tracks)
116                 BLI_freelinkN(tracks, nlt);
117         else
118                 MEM_freeN(nlt);
119 }
120
121 /* Free the elements of type NLA Tracks provided in the given list, but do not free
122  * the list itself since that is not free-standing
123  */
124 void free_nladata (ListBase *tracks)
125 {
126         NlaTrack *nlt, *nltn;
127         
128         /* sanity checks */
129         if ELEM(NULL, tracks, tracks->first)
130                 return;
131                 
132         /* free tracks one by one */
133         for (nlt= tracks->first; nlt; nlt= nltn) {
134                 nltn= nlt->next;
135                 free_nlatrack(tracks, nlt);
136         }
137         
138         /* clear the list's pointers to be safe */
139         tracks->first= tracks->last= NULL;
140 }
141
142 /* Copying ------------------------------------------- */
143
144 /* Copy NLA strip */
145 NlaStrip *copy_nlastrip (NlaStrip *strip)
146 {
147         NlaStrip *strip_d;
148         
149         /* sanity check */
150         if (strip == NULL)
151                 return NULL;
152                 
153         /* make a copy */
154         strip_d= MEM_dupallocN(strip);
155         strip_d->next= strip_d->prev= NULL;
156         
157         /* increase user-count of action */
158         if (strip_d->act)
159                 strip_d->act->id.us++;
160                 
161         /* copy F-Curves and modifiers */
162         copy_fcurves(&strip_d->fcurves, &strip->fcurves);
163         copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
164         
165         /* return the strip */
166         return strip_d;
167 }
168
169 /* Copy NLA Track */
170 NlaTrack *copy_nlatrack (NlaTrack *nlt)
171 {
172         NlaStrip *strip, *strip_d;
173         NlaTrack *nlt_d;
174         
175         /* sanity check */
176         if (nlt == NULL)
177                 return NULL;
178                 
179         /* make a copy */
180         nlt_d= MEM_dupallocN(nlt);
181         nlt_d->next= nlt_d->prev= NULL;
182         
183         /* make a copy of all the strips, one at a time */
184         nlt_d->strips.first= nlt_d->strips.last= NULL;
185         
186         for (strip= nlt->strips.first; strip; strip= strip->next) {
187                 strip_d= copy_nlastrip(strip);
188                 BLI_addtail(&nlt_d->strips, strip_d);
189         }
190         
191         /* return the copy */
192         return nlt_d;
193 }
194
195 /* Copy all NLA data */
196 void copy_nladata (ListBase *dst, ListBase *src)
197 {
198         NlaTrack *nlt, *nlt_d;
199         
200         /* sanity checks */
201         if ELEM(NULL, dst, src)
202                 return;
203                 
204         /* copy each NLA-track, one at a time */
205         for (nlt= src->first; nlt; nlt= nlt->next) {
206                 /* make a copy, and add the copy to the destination list */
207                 nlt_d= copy_nlatrack(nlt);
208                 BLI_addtail(dst, nlt_d);
209         }
210 }
211
212 /* Adding ------------------------------------------- */
213
214 /* Add a NLA Track to the given AnimData 
215  *      - prev: NLA-Track to add the new one after
216  */
217 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
218 {
219         NlaTrack *nlt;
220         
221         /* sanity checks */
222         if (adt == NULL)
223                 return NULL;
224                 
225         /* allocate new track */
226         nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
227         
228         /* set settings requiring the track to not be part of the stack yet */
229         nlt->flag = NLATRACK_SELECTED;
230         nlt->index= BLI_countlist(&adt->nla_tracks);
231         
232         /* add track to stack, and make it the active one */
233         if (prev)
234                 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
235         else
236                 BLI_addtail(&adt->nla_tracks, nlt);
237         BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
238         
239         /* must have unique name, but we need to seed this */
240         sprintf(nlt->name, "NlaTrack");
241         BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64);
242         
243         /* return the new track */
244         return nlt;
245 }
246
247 /* Add a NLA Strip referencing the given Action */
248 NlaStrip *add_nlastrip (bAction *act)
249 {
250         NlaStrip *strip;
251         
252         /* sanity checks */
253         if (act == NULL)
254                 return NULL;
255                 
256         /* allocate new strip */
257         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
258         
259         /* generic settings 
260          *      - selected flag to highlight this to the user
261          *      - auto-blends to ensure that blend in/out values are automatically 
262          *        determined by overlaps of strips
263          *      - (XXX) synchronisation of strip-length in accordance with changes to action-length
264          *        is not done though, since this should only really happens in editmode for strips now
265          *        though this decision is still subject to further review...
266          */
267         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
268         
269         /* assign the action reference */
270         strip->act= act;
271         id_us_plus(&act->id);
272         
273         /* determine initial range 
274          *      - strip length cannot be 0... ever...
275          */
276         calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
277         
278         strip->start = strip->actstart;
279         strip->end = (IS_EQ(strip->actstart, strip->actend)) ?  (strip->actstart + 1.0f): (strip->actend);
280         
281         /* strip should be referenced as-is */
282         strip->scale= 1.0f;
283         strip->repeat = 1.0f;
284         
285         /* return the new strip */
286         return strip;
287 }
288
289 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
290 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
291 {
292         NlaStrip *strip;
293         NlaTrack *nlt;
294         
295         /* sanity checks */
296         if ELEM(NULL, adt, act)
297                 return NULL;
298         
299         /* create a new NLA strip */
300         strip= add_nlastrip(act);
301         if (strip == NULL)
302                 return NULL;
303         
304         /* firstly try adding strip to last track, but if that fails, add to a new track */
305         if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
306                 /* trying to add to the last track failed (no track or no space), 
307                  * so add a new track to the stack, and add to that...
308                  */
309                 nlt= add_nlatrack(adt, NULL);
310                 BKE_nlatrack_add_strip(nlt, strip);
311         }
312         
313         /* returns the strip added */
314         return strip;
315 }
316
317 /* *************************************************** */
318 /* NLA Evaluation <-> Editing Stuff */
319
320 /* Strip Mapping ------------------------------------- */
321
322 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
323  *      invert = convert action-strip time to global time 
324  */
325 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode)
326 {
327         float actlength, repeat, scale;
328         
329         /* get number of repeats */
330         if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f;
331         repeat = strip->repeat;
332         
333         /* scaling */
334         if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f;
335         scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
336         
337         /* length of referenced action */
338         actlength = strip->actend - strip->actstart;
339         if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
340         
341         /* reversed = play strip backwards */
342         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
343                 // FIXME: this won't work right with Graph Editor?
344                 if (mode == NLATIME_CONVERT_MAP) {
345                         return strip->end - scale*(cframe - strip->actstart);
346                 }
347                 else if (mode == NLATIME_CONVERT_UNMAP) {
348                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
349                         
350                         /* this method doesn't clip the values to lie within the action range only 
351                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
352                          *      - the fmod(...) works in the same way as for eval 
353                          */
354                         return strip->actend - (repeatsNum * actlength * scale) 
355                                         - (fmod(cframe - strip->start, actlength*scale) / scale);
356                 }
357                 else {
358                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
359                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
360                                  * by catching the case where repeats is a whole number, which means that the end of the strip
361                                  * could also be interpreted as the end of the start of a repeat
362                                  */
363                                 return strip->actstart;
364                         }
365                         else {
366                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
367                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
368                                  */
369                                 return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; 
370                         }
371                 }
372         }
373         else {
374                 if (mode == NLATIME_CONVERT_MAP) {
375                         return strip->start + scale*(cframe - strip->actstart);
376                 }
377                 else if (mode == NLATIME_CONVERT_UNMAP) {
378                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
379                         
380                         /* this method doesn't clip the values to lie within the action range only 
381                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
382                          *      - the fmod(...) works in the same way as for eval 
383                          */
384                         return strip->actstart + (repeatsNum * actlength * scale) 
385                                         + (fmod(cframe - strip->start, actlength*scale) / scale);
386                 }
387                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
388                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
389                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
390                                  * by catching the case where repeats is a whole number, which means that the end of the strip
391                                  * could also be interpreted as the end of the start of a repeat
392                                  */
393                                 return strip->actend;
394                         }
395                         else {
396                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
397                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
398                                  */
399                                 return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale; 
400                         }
401                 }
402         }
403 }
404
405 /* non clipped mapping for strip-time <-> global time (for Transitions)
406  *      invert = convert action-strip time to global time 
407  */
408 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
409 {
410         float length;
411         
412         /* length of strip */
413         length= strip->end - strip->start;
414         
415         /* reversed = play strip backwards */
416         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
417                 if (mode == NLATIME_CONVERT_MAP)
418                         return strip->end - (length * cframe);
419                 else
420                         return (strip->end - cframe) / length;
421         }
422         else {
423                 if (mode == NLATIME_CONVERT_MAP)
424                         return (length * cframe) + strip->start;
425                 else
426                         return (cframe - strip->start) / length;
427         }
428 }
429
430 /* non clipped mapping for strip-time <-> global time
431  *      mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
432  *
433  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
434  * but should not be directly relied on for stuff which interacts with editors
435  */
436 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
437 {
438         switch (strip->type) {
439                 case NLASTRIP_TYPE_TRANSITION: /* transition */
440                         return nlastrip_get_frame_transition(strip, cframe, mode);
441                 
442                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
443                 default:
444                         return nlastrip_get_frame_actionclip(strip, cframe, mode);
445         }       
446 }
447
448
449 /* Non clipped mapping for strip-time <-> global time
450  *      mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
451  *
452  * Public API method - perform this mapping using the given AnimData block
453  * and perform any necessary sanity checks on the value
454  */
455 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
456 {
457         NlaStrip *strip;
458         
459         /* sanity checks 
460          *      - obviously we've got to have some starting data
461          *      - when not in tweakmode, the active Action does not have any scaling applied :)
462          */
463         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0)
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                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
797                 }
798         }
799 }
800
801
802 /* Find the active strip + track combo, and set them up as the tweaking track,
803  * and return if successful or not.
804  */
805 short BKE_nla_tweakmode_enter (AnimData *adt)
806 {
807         NlaTrack *nlt, *activeTrack=NULL;
808         NlaStrip *strip, *activeStrip=NULL;
809         
810         /* verify that data is valid */
811         if ELEM(NULL, adt, adt->nla_tracks.first)
812                 return 0;
813                 
814         /* if block is already in tweakmode, just leave, but we should report 
815          * that this block is in tweakmode (as our returncode)
816          */
817         if (adt->flag & ADT_NLA_EDIT_ON)
818                 return 1;
819                 
820         /* go over the tracks, finding the active one, and its active strip
821          *      - if we cannot find both, then there's nothing to do
822          */
823         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
824                 /* check if active */
825                 if (nlt->flag & NLATRACK_ACTIVE) {
826                         /* store reference to this active track */
827                         activeTrack= nlt;
828                         
829                         /* now try to find active strip */
830                         activeStrip= BKE_nlastrip_find_active(nlt);
831                         break;
832                 }       
833         }
834         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
835                 printf("NLA tweakmode enter - neither active requirement found \n");
836                 return 0;
837         }
838                 
839         /* go over all the tracks up to the active one, tagging each strip that uses the same 
840          * action as the active strip, but leaving everything else alone
841          */
842         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
843                 for (strip= nlt->strips.first; strip; strip= strip->next) {
844                         if (strip->act == activeStrip->act)
845                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
846                         else
847                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; // XXX probably don't need to clear this...
848                 }
849         }
850         
851         
852         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
853          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
854          */
855         for (nlt= activeTrack; nlt; nlt= nlt->next)
856                 nlt->flag |= NLATRACK_DISABLED;
857         
858         /* handle AnimData level changes:
859          *      - 'real' active action to temp storage (no need to change user-counts)
860          *      - action of active strip set to be the 'active action', and have its usercount incremented
861          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
862          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
863          */
864         adt->tmpact= adt->action;
865         adt->action= activeStrip->act;
866         adt->actstrip= activeStrip;
867         id_us_plus(&activeStrip->act->id);
868         adt->flag |= ADT_NLA_EDIT_ON;
869         
870         /* done! */
871         return 1;
872 }
873
874 /* Exit tweakmode for this AnimData block */
875 void BKE_nla_tweakmode_exit (AnimData *adt)
876 {
877         NlaStrip *strip;
878         NlaTrack *nlt;
879         
880         /* verify that data is valid */
881         if ELEM(NULL, adt, adt->nla_tracks.first)
882                 return;
883                 
884         /* hopefully the flag is correct - skip if not on */
885         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
886                 return;
887                 
888         // TODO: need to sync the user-strip with the new state of the action!
889                 
890         /* for all NLA-tracks, clear the 'disabled' flag
891          * for all NLA-strips, clear the 'tweak-user' flag
892          */
893         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
894                 nlt->flag &= ~NLATRACK_DISABLED;
895                 
896                 for (strip= nlt->strips.first; strip; strip= strip->next) 
897                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
898         }
899         
900         /* handle AnimData level changes:
901          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
902          *      - 'real' active action is restored from storage
903          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
904          *      - editing-flag for this AnimData block should also get turned off
905          *      - clear pointer to active strip
906          */
907         if (adt->action) adt->action->id.us--;
908         adt->action= adt->tmpact;
909         adt->tmpact= NULL;
910         adt->actstrip= NULL;
911         adt->flag &= ~ADT_NLA_EDIT_ON;
912 }
913
914 /* *************************************************** */