NLA SoC: NLA Mapping Cleanup
[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 mode)
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                 // FIXME: this won't work right with Graph Editor?
351                 if (mode == NLATIME_CONVERT_MAP) {
352                         return strip->end - scale*(cframe - strip->actstart);
353                 }
354                 else if (mode == NLATIME_CONVERT_UNMAP) {
355                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
356                         
357                         /* this method doesn't clip the values to lie within the action range only 
358                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
359                          *      - the fmod(...) works in the same way as for eval 
360                          */
361                         return strip->actend - (repeatsNum * actlength * scale) 
362                                         - (fmod(cframe - strip->start, actlength*scale) / scale);
363                 }
364                 else {
365                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
366                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
367                                  * by catching the case where repeats is a whole number, which means that the end of the strip
368                                  * could also be interpreted as the end of the start of a repeat
369                                  */
370                                 return strip->actstart;
371                         }
372                         else {
373                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
374                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
375                                  */
376                                 return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; 
377                         }
378                 }
379         }
380         else {
381                 if (mode == NLATIME_CONVERT_MAP) {
382                         return strip->start + scale*(cframe - strip->actstart);
383                 }
384                 else if (mode == NLATIME_CONVERT_UNMAP) {
385                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
386                         
387                         /* this method doesn't clip the values to lie within the action range only 
388                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
389                          *      - the fmod(...) works in the same way as for eval 
390                          */
391                         return strip->actstart + (repeatsNum * actlength * scale) 
392                                         + (fmod(cframe - strip->start, actlength*scale) / scale);
393                 }
394                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
395                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
396                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
397                                  * by catching the case where repeats is a whole number, which means that the end of the strip
398                                  * could also be interpreted as the end of the start of a repeat
399                                  */
400                                 return strip->actend;
401                         }
402                         else {
403                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
404                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
405                                  */
406                                 return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale; 
407                         }
408                 }
409         }
410 }
411
412 /* non clipped mapping for strip-time <-> global time (for Transitions)
413  *      invert = convert action-strip time to global time 
414  */
415 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
416 {
417         float length;
418         
419         /* length of strip */
420         length= strip->end - strip->start;
421         
422         /* reversed = play strip backwards */
423         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
424                 if (mode == NLATIME_CONVERT_MAP)
425                         return strip->end - (length * cframe);
426                 else
427                         return (strip->end - cframe) / length;
428         }
429         else {
430                 if (mode == NLATIME_CONVERT_MAP)
431                         return (length * cframe) + strip->start;
432                 else
433                         return (cframe - strip->start) / length;
434         }
435 }
436
437 /* non clipped mapping for strip-time <-> global time
438  *      mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
439  *
440  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
441  * but should not be directly relied on for stuff which interacts with editors
442  */
443 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
444 {
445         switch (strip->type) {
446                 case NLASTRIP_TYPE_TRANSITION: /* transition */
447                         return nlastrip_get_frame_transition(strip, cframe, mode);
448                 
449                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
450                 default:
451                         return nlastrip_get_frame_actionclip(strip, cframe, mode);
452         }       
453 }
454
455
456 /* Non clipped mapping for strip-time <-> global time
457  *      mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
458  *
459  * Public API method - perform this mapping using the given AnimData block
460  * and perform any necessary sanity checks on the value
461  */
462 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
463 {
464         NlaStrip *strip;
465         
466         /* sanity checks 
467          *      - obviously we've got to have some starting data
468          *      - when not in tweakmode, the active Action does not have any scaling applied :)
469          */
470         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0)
471                 return cframe;
472                 
473         /* if the active-strip info has been stored already, access this, otherwise look this up
474          * and store for (very probable) future usage
475          */
476         if (adt->actstrip == NULL) {
477                 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
478                 adt->actstrip= BKE_nlastrip_find_active(nlt);
479         }
480         strip= adt->actstrip;
481         
482         /* sanity checks 
483          *      - in rare cases, we may not be able to find this strip for some reason (internal error)
484          *      - for now, if the user has defined a curve to control the time, this correction cannot be performed
485          *        reliably...
486          */
487         if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
488                 return cframe;
489                 
490         /* perform the correction now... */
491         return nlastrip_get_frame(strip, cframe, mode);
492 }
493
494 /* *************************************************** */
495 /* Basic Utilities */
496
497 /* NLA-Tracks ---------------------------------------- */
498
499 /* Find the active NLA-track for the given stack */
500 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
501 {
502         NlaTrack *nlt;
503         
504         /* sanity check */
505         if ELEM(NULL, tracks, tracks->first)
506                 return NULL;
507                 
508         /* try to find the first active track */
509         for (nlt= tracks->first; nlt; nlt= nlt->next) {
510                 if (nlt->flag & NLATRACK_ACTIVE)
511                         return nlt;
512         }
513         
514         /* none found */
515         return NULL;
516 }
517
518 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
519  * that has this status in its AnimData block.
520  */
521 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
522 {
523         NlaTrack *nt;
524         
525         /* sanity check */
526         if ELEM(NULL, adt, adt->nla_tracks.first)
527                 return;
528                 
529         /* firstly, make sure 'solo' flag for all tracks is disabled */
530         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
531                 if (nt != nlt)
532                         nt->flag &= ~NLATRACK_SOLO;
533         }
534                 
535         /* now, enable 'solo' for the given track if appropriate */
536         if (nlt) {
537                 /* toggle solo status */
538                 nlt->flag ^= NLATRACK_SOLO;
539                 
540                 /* set or clear solo-status on AnimData */
541                 if (nlt->flag & NLATRACK_SOLO)
542                         adt->flag |= ADT_NLA_SOLO_TRACK;
543                 else
544                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
545         }
546         else
547                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
548 }
549
550 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
551  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
552  */
553 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
554 {
555         NlaTrack *nlt;
556         
557         /* sanity check */
558         if ELEM(NULL, tracks, tracks->first)
559                 return;
560         
561         /* deactive all the rest */
562         for (nlt= tracks->first; nlt; nlt= nlt->next) 
563                 nlt->flag &= ~NLATRACK_ACTIVE;
564                 
565         /* set the given one as the active one */
566         if (nlt_a)
567                 nlt_a->flag |= NLATRACK_ACTIVE;
568 }
569
570 /* Check if there is any space in the last track to add the given strip */
571 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
572 {
573         NlaStrip *strip;
574         
575         /* sanity checks */
576         if ((nlt == NULL) || IS_EQ(start, end))
577                 return 0;
578         if (start > end) {
579                 puts("BKE_nlatrack_has_space error... start and end arguments swapped");
580                 SWAP(float, start, end);
581         }
582         
583         /* loop over NLA strips checking for any overlaps with this area... */
584         for (strip= nlt->strips.first; strip; strip= strip->next) {
585                 /* if start frame of strip is past the target end-frame, that means that
586                  * we've gone past the window we need to check for, so things are fine
587                  */
588                 if (strip->start > end)
589                         return 1;
590                 
591                 /* if the end of the strip is greater than either of the boundaries, the range
592                  * must fall within the extents of the strip
593                  */
594                 if ((strip->end > start) || (strip->end > end))
595                         return 0;
596         }
597         
598         /* if we are still here, we haven't encountered any overlapping strips */
599         return 1;
600 }
601
602 /* Rearrange the strips in the track so that they are always in order 
603  * (usually only needed after a strip has been moved) 
604  */
605 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
606 {
607         ListBase tmp = {NULL, NULL};
608         NlaStrip *strip, *sstrip;
609         
610         /* sanity checks */
611         if ELEM(NULL, nlt, nlt->strips.first)
612                 return;
613                 
614         /* we simply perform insertion sort on this list, since it is assumed that per track,
615          * there are only likely to be at most 5-10 strips
616          */
617         for (strip= nlt->strips.first; strip; strip= strip->next) {
618                 short not_added = 1;
619                 
620                 /* remove this strip from the list, and add it to the new list, searching from the end of 
621                  * the list, assuming that the lists are in order 
622                  */
623                 BLI_remlink(&nlt->strips, strip);
624                 
625                 for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) {
626                         /* check if add after */
627                         if (sstrip->end < strip->start) {
628                                 BLI_insertlinkafter(&tmp, sstrip, strip);
629                                 not_added= 0;
630                                 break;
631                         }
632                 }
633                 
634                 /* add before first? */
635                 if (not_added)
636                         BLI_addhead(&tmp, strip);
637         }
638         
639         /* reassign the start and end points of the strips */
640         nlt->strips.first= tmp.first;
641         nlt->strips.last= tmp.last;
642 }
643
644 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
645  * isn't currently attached to another one 
646  */
647 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
648 {
649         NlaStrip *ns;
650         short not_added = 1;
651         
652         /* sanity checks */
653         if ELEM(NULL, nlt, strip)
654                 return 0;
655                 
656         /* check if any space to add */
657         if (BKE_nlatrack_has_space(nlt, strip->start, strip->end)==0)
658                 return 0;
659         
660         /* find the right place to add the strip to the nominated track */
661         for (ns= nlt->strips.first; ns; ns= ns->next) {
662                 /* if current strip occurs after the new strip, add it before */
663                 if (ns->start > strip->end) {
664                         BLI_insertlinkbefore(&nlt->strips, ns, strip);
665                         not_added= 0;
666                         break;
667                 }
668         }
669         if (not_added) {
670                 /* just add to the end of the list of the strips then... */
671                 BLI_addtail(&nlt->strips, strip);
672         }
673         
674         /* added... */
675         return 1;
676 }
677
678 /* NLA Strips -------------------------------------- */
679
680 /* Find the active NLA-strip within the given track */
681 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
682 {
683         NlaStrip *strip;
684         
685         /* sanity check */
686         if ELEM(NULL, nlt, nlt->strips.first)
687                 return NULL;
688                 
689         /* try to find the first active strip */
690         for (strip= nlt->strips.first; strip; strip= strip->next) {
691                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
692                         return strip;
693         }
694         
695         /* none found */
696         return NULL;
697 }
698
699 /* Does the given NLA-strip fall within the given bounds (times)? */
700 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
701 {
702         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
703         const float boundsLen= (float)fabs(max - min);
704         
705         /* sanity checks */
706         if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
707                 return 0;
708         
709         /* only ok if at least part of the strip is within the bounding window
710          *      - first 2 cases cover when the strip length is less than the bounding area
711          *      - second 2 cases cover when the strip length is greater than the bounding area
712          */
713         if ( (stripLen < boundsLen) && 
714                  !(IN_RANGE(strip->start, min, max) ||
715                    IN_RANGE(strip->end, min, max)) )
716         {
717                 return 0;
718         }
719         if ( (stripLen > boundsLen) && 
720                  !(IN_RANGE(min, strip->start, strip->end) ||
721                    IN_RANGE(max, strip->start, strip->end)) )
722         {
723                 return 0;
724         }
725         
726         /* should be ok! */
727         return 1;
728 }
729
730 /* Is the given NLA-strip the first one to occur for the given AnimData block */
731 // TODO: make this an api method if necesary, but need to add prefix first
732 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
733 {
734         NlaTrack *nlt;
735         NlaStrip *ns;
736         
737         /* sanity checks */
738         if ELEM(NULL, adt, strip)
739                 return 0;
740                 
741         /* check if strip has any strips before it */
742         if (strip->prev)
743                 return 0;
744                 
745         /* check other tracks to see if they have a strip that's earlier */
746         // TODO: or should we check that the strip's track is also the first?
747         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
748                 /* only check the first strip, assuming that they're all in order */
749                 ns= nlt->strips.first;
750                 if (ns) {
751                         if (ns->start < strip->start)
752                                 return 0;
753                 }
754         }       
755         
756         /* should be first now */
757         return 1;
758 }
759  
760 /* Tools ------------------------------------------- */
761
762 /* For the given AnimData block, add the active action to the NLA
763  * stack (i.e. 'push-down' action). The UI should only allow this 
764  * for normal editing only (i.e. not in editmode for some strip's action),
765  * so no checks for this are performed.
766  */
767 // TODO: maybe we should have checks for this too...
768 void BKE_nla_action_pushdown (AnimData *adt)
769 {
770         NlaStrip *strip;
771         
772         /* sanity checks */
773         // TODO: need to report the error for this
774         if ELEM(NULL, adt, adt->action) 
775                 return;
776                 
777         /* if the action is empty, we also shouldn't try to add to stack, 
778          * as that will cause us grief down the track
779          */
780         // TODO: what about modifiers?
781         if (action_has_motion(adt->action) == 0) {
782                 printf("BKE_nla_action_pushdown(): action has no data \n");
783                 return;
784         }
785         
786         /* add a new NLA strip to the track, which references the active action */
787         strip= add_nlastrip_to_stack(adt, adt->action);
788         
789         /* do other necessary work on strip */  
790         if (strip) {
791                 /* clear reference to action now that we've pushed it onto the stack */
792                 adt->action->id.us--;
793                 adt->action= NULL;
794                 
795                 /* if the strip is the first one in the track it lives in, check if there
796                  * are strips in any other tracks that may be before this, and set the extend
797                  * mode accordingly
798                  */
799                 if (nlastrip_is_first(adt, strip) == 0) {
800                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
801                          * so that it doesn't override strips in previous tracks
802                          */
803                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
804                 }
805         }
806 }
807
808
809 /* Find the active strip + track combo, and set them up as the tweaking track,
810  * and return if successful or not.
811  */
812 short BKE_nla_tweakmode_enter (AnimData *adt)
813 {
814         NlaTrack *nlt, *activeTrack=NULL;
815         NlaStrip *strip, *activeStrip=NULL;
816         
817         /* verify that data is valid */
818         if ELEM(NULL, adt, adt->nla_tracks.first)
819                 return 0;
820                 
821         /* if block is already in tweakmode, just leave, but we should report 
822          * that this block is in tweakmode (as our returncode)
823          */
824         if (adt->flag & ADT_NLA_EDIT_ON)
825                 return 1;
826                 
827         /* go over the tracks, finding the active one, and its active strip
828          *      - if we cannot find both, then there's nothing to do
829          */
830         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
831                 /* check if active */
832                 if (nlt->flag & NLATRACK_ACTIVE) {
833                         /* store reference to this active track */
834                         activeTrack= nlt;
835                         
836                         /* now try to find active strip */
837                         activeStrip= BKE_nlastrip_find_active(nlt);
838                         break;
839                 }       
840         }
841         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
842                 printf("NLA tweakmode enter - neither active requirement found \n");
843                 return 0;
844         }
845                 
846         /* go over all the tracks up to the active one, tagging each strip that uses the same 
847          * action as the active strip, but leaving everything else alone
848          */
849         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
850                 for (strip= nlt->strips.first; strip; strip= strip->next) {
851                         if (strip->act == activeStrip->act)
852                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
853                         else
854                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; // XXX probably don't need to clear this...
855                 }
856         }
857         
858         
859         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
860          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
861          */
862         for (nlt= activeTrack; nlt; nlt= nlt->next)
863                 nlt->flag |= NLATRACK_DISABLED;
864         
865         /* handle AnimData level changes:
866          *      - 'real' active action to temp storage (no need to change user-counts)
867          *      - action of active strip set to be the 'active action', and have its usercount incremented
868          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
869          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
870          */
871         adt->tmpact= adt->action;
872         adt->action= activeStrip->act;
873         adt->actstrip= activeStrip;
874         id_us_plus(&activeStrip->act->id);
875         adt->flag |= ADT_NLA_EDIT_ON;
876         
877         /* done! */
878         return 1;
879 }
880
881 /* Exit tweakmode for this AnimData block */
882 void BKE_nla_tweakmode_exit (AnimData *adt)
883 {
884         NlaStrip *strip;
885         NlaTrack *nlt;
886         
887         /* verify that data is valid */
888         if ELEM(NULL, adt, adt->nla_tracks.first)
889                 return;
890                 
891         /* hopefully the flag is correct - skip if not on */
892         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
893                 return;
894                 
895         // TODO: need to sync the user-strip with the new state of the action!
896                 
897         /* for all NLA-tracks, clear the 'disabled' flag
898          * for all NLA-strips, clear the 'tweak-user' flag
899          */
900         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
901                 nlt->flag &= ~NLATRACK_DISABLED;
902                 
903                 for (strip= nlt->strips.first; strip; strip= strip->next) 
904                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
905         }
906         
907         /* handle AnimData level changes:
908          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
909          *      - 'real' active action is restored from storage
910          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
911          *      - editing-flag for this AnimData block should also get turned off
912          *      - clear pointer to active strip
913          */
914         if (adt->action) adt->action->id.us--;
915         adt->action= adt->tmpact;
916         adt->tmpact= NULL;
917         adt->actstrip= NULL;
918         adt->flag &= ~ADT_NLA_EDIT_ON;
919 }
920
921 /* *************************************************** */