Merge from 2.5 -r 21285:21515. Thanks Joshua!
[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 <string.h>
34 #include <math.h>
35 #include <float.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_ghash.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44
45 #include "BKE_animsys.h"
46 #include "BKE_action.h"
47 #include "BKE_fcurve.h"
48 #include "BKE_nla.h"
49 #include "BKE_blender.h"
50 #include "BKE_library.h"
51 #include "BKE_object.h"
52 #include "BKE_utildefines.h"
53
54 #include "RNA_access.h"
55 #include "nla_private.h"
56
57
58 #ifdef HAVE_CONFIG_H
59 #include <config.h>
60 #endif
61
62
63 /* *************************************************** */
64 /* Data Management */
65
66 /* Freeing ------------------------------------------- */
67
68 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
69  * and the strip itself. 
70  */
71 void free_nlastrip (ListBase *strips, NlaStrip *strip)
72 {
73         NlaStrip *cs, *csn;
74         
75         /* sanity checks */
76         if (strip == NULL)
77                 return;
78                 
79         /* free child-strips */
80         for (cs= strip->strips.first; cs; cs= csn) {
81                 csn= cs->next;
82                 free_nlastrip(&strip->strips, cs);
83         }
84                 
85         /* remove reference to action */
86         if (strip->act)
87                 strip->act->id.us--;
88                 
89         /* free remapping info */
90         //if (strip->remap)
91         //      BKE_animremap_free();
92         
93         /* free own F-Curves */
94         free_fcurves(&strip->fcurves);
95         
96         /* free own F-Modifiers */
97         free_fmodifiers(&strip->modifiers);
98         
99         /* free the strip itself */
100         if (strips)
101                 BLI_freelinkN(strips, strip);
102         else
103                 MEM_freeN(strip);
104 }
105
106 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
107  * and the track itself.
108  */
109 void free_nlatrack (ListBase *tracks, NlaTrack *nlt)
110 {
111         NlaStrip *strip, *stripn;
112         
113         /* sanity checks */
114         if (nlt == NULL)
115                 return;
116                 
117         /* free strips */
118         for (strip= nlt->strips.first; strip; strip= stripn) {
119                 stripn= strip->next;
120                 free_nlastrip(&nlt->strips, strip);
121         }
122         
123         /* free NLA track itself now */
124         if (tracks)
125                 BLI_freelinkN(tracks, nlt);
126         else
127                 MEM_freeN(nlt);
128 }
129
130 /* Free the elements of type NLA Tracks provided in the given list, but do not free
131  * the list itself since that is not free-standing
132  */
133 void free_nladata (ListBase *tracks)
134 {
135         NlaTrack *nlt, *nltn;
136         
137         /* sanity checks */
138         if ELEM(NULL, tracks, tracks->first)
139                 return;
140                 
141         /* free tracks one by one */
142         for (nlt= tracks->first; nlt; nlt= nltn) {
143                 nltn= nlt->next;
144                 free_nlatrack(tracks, nlt);
145         }
146         
147         /* clear the list's pointers to be safe */
148         tracks->first= tracks->last= NULL;
149 }
150
151 /* Copying ------------------------------------------- */
152
153 /* Copy NLA strip */
154 NlaStrip *copy_nlastrip (NlaStrip *strip)
155 {
156         NlaStrip *strip_d;
157         NlaStrip *cs, *cs_d;
158         
159         /* sanity check */
160         if (strip == NULL)
161                 return NULL;
162                 
163         /* make a copy */
164         strip_d= MEM_dupallocN(strip);
165         strip_d->next= strip_d->prev= NULL;
166         
167         /* increase user-count of action */
168         if (strip_d->act)
169                 strip_d->act->id.us++;
170                 
171         /* copy F-Curves and modifiers */
172         copy_fcurves(&strip_d->fcurves, &strip->fcurves);
173         copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
174         
175         /* make a copy of all the child-strips, one at a time */
176         strip_d->strips.first= strip_d->strips.last= NULL;
177         
178         for (cs= strip->strips.first; cs; cs= cs->next) {
179                 cs_d= copy_nlastrip(cs);
180                 BLI_addtail(&strip_d->strips, cs_d);
181         }
182         
183         /* return the strip */
184         return strip_d;
185 }
186
187 /* Copy NLA Track */
188 NlaTrack *copy_nlatrack (NlaTrack *nlt)
189 {
190         NlaStrip *strip, *strip_d;
191         NlaTrack *nlt_d;
192         
193         /* sanity check */
194         if (nlt == NULL)
195                 return NULL;
196                 
197         /* make a copy */
198         nlt_d= MEM_dupallocN(nlt);
199         nlt_d->next= nlt_d->prev= NULL;
200         
201         /* make a copy of all the strips, one at a time */
202         nlt_d->strips.first= nlt_d->strips.last= NULL;
203         
204         for (strip= nlt->strips.first; strip; strip= strip->next) {
205                 strip_d= copy_nlastrip(strip);
206                 BLI_addtail(&nlt_d->strips, strip_d);
207         }
208         
209         /* return the copy */
210         return nlt_d;
211 }
212
213 /* Copy all NLA data */
214 void copy_nladata (ListBase *dst, ListBase *src)
215 {
216         NlaTrack *nlt, *nlt_d;
217         
218         /* sanity checks */
219         if ELEM(NULL, dst, src)
220                 return;
221                 
222         /* copy each NLA-track, one at a time */
223         for (nlt= src->first; nlt; nlt= nlt->next) {
224                 /* make a copy, and add the copy to the destination list */
225                 nlt_d= copy_nlatrack(nlt);
226                 BLI_addtail(dst, nlt_d);
227         }
228 }
229
230 /* Adding ------------------------------------------- */
231
232 /* Add a NLA Track to the given AnimData 
233  *      - prev: NLA-Track to add the new one after
234  */
235 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
236 {
237         NlaTrack *nlt;
238         
239         /* sanity checks */
240         if (adt == NULL)
241                 return NULL;
242                 
243         /* allocate new track */
244         nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
245         
246         /* set settings requiring the track to not be part of the stack yet */
247         nlt->flag = NLATRACK_SELECTED;
248         nlt->index= BLI_countlist(&adt->nla_tracks);
249         
250         /* add track to stack, and make it the active one */
251         if (prev)
252                 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
253         else
254                 BLI_addtail(&adt->nla_tracks, nlt);
255         BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
256         
257         /* must have unique name, but we need to seed this */
258         sprintf(nlt->name, "NlaTrack");
259         BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64);
260         
261         /* return the new track */
262         return nlt;
263 }
264
265 /* Add a NLA Strip referencing the given Action */
266 NlaStrip *add_nlastrip (bAction *act)
267 {
268         NlaStrip *strip;
269         
270         /* sanity checks */
271         if (act == NULL)
272                 return NULL;
273                 
274         /* allocate new strip */
275         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
276         
277         /* generic settings 
278          *      - selected flag to highlight this to the user
279          *      - auto-blends to ensure that blend in/out values are automatically 
280          *        determined by overlaps of strips
281          *      - (XXX) synchronisation of strip-length in accordance with changes to action-length
282          *        is not done though, since this should only really happens in editmode for strips now
283          *        though this decision is still subject to further review...
284          */
285         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
286         
287         /* assign the action reference */
288         strip->act= act;
289         id_us_plus(&act->id);
290         
291         /* determine initial range 
292          *      - strip length cannot be 0... ever...
293          */
294         calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
295         
296         strip->start = strip->actstart;
297         strip->end = (IS_EQ(strip->actstart, strip->actend)) ?  (strip->actstart + 1.0f): (strip->actend);
298         
299         /* strip should be referenced as-is */
300         strip->scale= 1.0f;
301         strip->repeat = 1.0f;
302         
303         /* return the new strip */
304         return strip;
305 }
306
307 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
308 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
309 {
310         NlaStrip *strip;
311         NlaTrack *nlt;
312         
313         /* sanity checks */
314         if ELEM(NULL, adt, act)
315                 return NULL;
316         
317         /* create a new NLA strip */
318         strip= add_nlastrip(act);
319         if (strip == NULL)
320                 return NULL;
321         
322         /* firstly try adding strip to last track, but if that fails, add to a new track */
323         if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
324                 /* trying to add to the last track failed (no track or no space), 
325                  * so add a new track to the stack, and add to that...
326                  */
327                 nlt= add_nlatrack(adt, NULL);
328                 BKE_nlatrack_add_strip(nlt, strip);
329         }
330         
331         /* automatically name it too */
332         BKE_nlastrip_validate_name(adt, strip);
333         
334         /* returns the strip added */
335         return strip;
336 }
337
338 /* *************************************************** */
339 /* NLA Evaluation <-> Editing Stuff */
340
341 /* Strip Mapping ------------------------------------- */
342
343 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
344  *      invert = convert action-strip time to global time 
345  */
346 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode)
347 {
348         float actlength, repeat, scale;
349         
350         /* get number of repeats */
351         if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f;
352         repeat = strip->repeat;
353         
354         /* scaling */
355         if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f;
356         scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
357         
358         /* length of referenced action */
359         actlength = strip->actend - strip->actstart;
360         if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
361         
362         /* reversed = play strip backwards */
363         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
364                 // FIXME: this won't work right with Graph Editor?
365                 if (mode == NLATIME_CONVERT_MAP) {
366                         return strip->end - scale*(cframe - strip->actstart);
367                 }
368                 else if (mode == NLATIME_CONVERT_UNMAP) {
369                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
370                         
371                         /* this method doesn't clip the values to lie within the action range only 
372                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
373                          *      - the fmod(...) works in the same way as for eval 
374                          */
375                         return strip->actend - (repeatsNum * actlength * scale) 
376                                         - (fmod(cframe - strip->start, actlength*scale) / scale);
377                 }
378                 else {
379                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
380                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
381                                  * by catching the case where repeats is a whole number, which means that the end of the strip
382                                  * could also be interpreted as the end of the start of a repeat
383                                  */
384                                 return strip->actstart;
385                         }
386                         else {
387                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
388                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
389                                  */
390                                 return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; 
391                         }
392                 }
393         }
394         else {
395                 if (mode == NLATIME_CONVERT_MAP) {
396                         return strip->start + scale*(cframe - strip->actstart);
397                 }
398                 else if (mode == NLATIME_CONVERT_UNMAP) {
399                         int repeatsNum = (int)((cframe - strip->start) / (actlength * scale));
400                         
401                         /* this method doesn't clip the values to lie within the action range only 
402                          *      - the '(repeatsNum * actlength * scale)' compensates for the fmod(...)
403                          *      - the fmod(...) works in the same way as for eval 
404                          */
405                         return strip->actstart + (repeatsNum * actlength * scale) 
406                                         + (fmod(cframe - strip->start, actlength*scale) / scale);
407                 }
408                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
409                         if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) {
410                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
411                                  * by catching the case where repeats is a whole number, which means that the end of the strip
412                                  * could also be interpreted as the end of the start of a repeat
413                                  */
414                                 return strip->actend;
415                         }
416                         else {
417                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
418                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
419                                  */
420                                 return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale; 
421                         }
422                 }
423         }
424 }
425
426 /* non clipped mapping for strip-time <-> global time (for Transitions)
427  *      invert = convert action-strip time to global time 
428  */
429 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
430 {
431         float length;
432         
433         /* length of strip */
434         length= strip->end - strip->start;
435         
436         /* reversed = play strip backwards */
437         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
438                 if (mode == NLATIME_CONVERT_MAP)
439                         return strip->end - (length * cframe);
440                 else
441                         return (strip->end - cframe) / length;
442         }
443         else {
444                 if (mode == NLATIME_CONVERT_MAP)
445                         return (length * cframe) + strip->start;
446                 else
447                         return (cframe - strip->start) / length;
448         }
449 }
450
451 /* non clipped mapping for strip-time <-> global time
452  *      mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
453  *
454  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
455  * but should not be directly relied on for stuff which interacts with editors
456  */
457 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
458 {
459         switch (strip->type) {
460                 case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
461                 case NLASTRIP_TYPE_TRANSITION: /* transition */
462                         return nlastrip_get_frame_transition(strip, cframe, mode);
463                 
464                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
465                 default:
466                         return nlastrip_get_frame_actionclip(strip, cframe, mode);
467         }       
468 }
469
470
471 /* Non clipped mapping for strip-time <-> global time
472  *      mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
473  *
474  * Public API method - perform this mapping using the given AnimData block
475  * and perform any necessary sanity checks on the value
476  */
477 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
478 {
479         NlaStrip *strip;
480         
481         /* sanity checks 
482          *      - obviously we've got to have some starting data
483          *      - when not in tweakmode, the active Action does not have any scaling applied :)
484          *      - when in tweakmode, if the no-mapping flag is set, do not map
485          */
486         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
487                 return cframe;
488                 
489         /* if the active-strip info has been stored already, access this, otherwise look this up
490          * and store for (very probable) future usage
491          */
492         if (adt->actstrip == NULL) {
493                 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
494                 adt->actstrip= BKE_nlastrip_find_active(nlt);
495         }
496         strip= adt->actstrip;
497         
498         /* sanity checks 
499          *      - in rare cases, we may not be able to find this strip for some reason (internal error)
500          *      - for now, if the user has defined a curve to control the time, this correction cannot be performed
501          *        reliably...
502          */
503         if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
504                 return cframe;
505                 
506         /* perform the correction now... */
507         return nlastrip_get_frame(strip, cframe, mode);
508 }
509
510 /* *************************************************** */
511 /* NLA API */
512
513 /* List of Strips ------------------------------------ */
514 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
515
516 /* Check if there is any space in the given list to add the given strip */
517 short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
518 {
519         NlaStrip *strip;
520         
521         /* sanity checks */
522         if ((strips == NULL) || IS_EQ(start, end))
523                 return 0;
524         if (start > end) {
525                 puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
526                 SWAP(float, start, end);
527         }
528         
529         /* loop over NLA strips checking for any overlaps with this area... */
530         for (strip= strips->first; strip; strip= strip->next) {
531                 /* if start frame of strip is past the target end-frame, that means that
532                  * we've gone past the window we need to check for, so things are fine
533                  */
534                 if (strip->start > end)
535                         return 1;
536                 
537                 /* if the end of the strip is greater than either of the boundaries, the range
538                  * must fall within the extents of the strip
539                  */
540                 if ((strip->end > start) || (strip->end > end))
541                         return 0;
542         }
543         
544         /* if we are still here, we haven't encountered any overlapping strips */
545         return 1;
546 }
547
548 /* Rearrange the strips in the track so that they are always in order 
549  * (usually only needed after a strip has been moved) 
550  */
551 void BKE_nlastrips_sort_strips (ListBase *strips)
552 {
553         ListBase tmp = {NULL, NULL};
554         NlaStrip *strip, *sstrip, *stripn;
555         
556         /* sanity checks */
557         if ELEM(NULL, strips, strips->first)
558                 return;
559         
560         /* we simply perform insertion sort on this list, since it is assumed that per track,
561          * there are only likely to be at most 5-10 strips
562          */
563         for (strip= strips->first; strip; strip= stripn) {
564                 short not_added = 1;
565                 
566                 stripn= strip->next;
567                 
568                 /* remove this strip from the list, and add it to the new list, searching from the end of 
569                  * the list, assuming that the lists are in order 
570                  */
571                 BLI_remlink(strips, strip);
572                 
573                 for (sstrip= tmp.last; sstrip; sstrip= sstrip->prev) {
574                         /* check if add after */
575                         if (sstrip->end <= strip->start) {
576                                 BLI_insertlinkafter(&tmp, sstrip, strip);
577                                 not_added= 0;
578                                 break;
579                         }
580                 }
581                 
582                 /* add before first? */
583                 if (not_added)
584                         BLI_addhead(&tmp, strip);
585         }
586         
587         /* reassign the start and end points of the strips */
588         strips->first= tmp.first;
589         strips->last= tmp.last;
590 }
591
592 /* Add the given NLA-Strip to the given list of strips, assuming that it 
593  * isn't currently a member of another list
594  */
595 short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
596 {
597         NlaStrip *ns;
598         short not_added = 1;
599         
600         /* sanity checks */
601         if ELEM(NULL, strips, strip)
602                 return 0;
603                 
604         /* check if any space to add */
605         if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0)
606                 return 0;
607         
608         /* find the right place to add the strip to the nominated track */
609         for (ns= strips->first; ns; ns= ns->next) {
610                 /* if current strip occurs after the new strip, add it before */
611                 if (ns->start > strip->end) {
612                         BLI_insertlinkbefore(strips, ns, strip);
613                         not_added= 0;
614                         break;
615                 }
616         }
617         if (not_added) {
618                 /* just add to the end of the list of the strips then... */
619                 BLI_addtail(strips, strip);
620         }
621         
622         /* added... */
623         return 1;
624 }
625
626
627 /* Meta-Strips ------------------------------------ */
628
629 /* Convert 'islands' (i.e. continuous string of) selected strips to be
630  * contained within 'Meta-Strips' which act as strips which contain strips.
631  *      temp: are the meta-strips to be created 'temporary' ones used for transforms?
632  */
633 void BKE_nlastrips_make_metas (ListBase *strips, short temp)
634 {
635         NlaStrip *mstrip = NULL;
636         NlaStrip *strip, *stripn;
637         
638         /* sanity checks */
639         if ELEM(NULL, strips, strips->first)
640                 return;
641         
642         /* group all continuous chains of selected strips into meta-strips */
643         for (strip= strips->first; strip; strip= stripn) {
644                 stripn= strip->next;
645                 
646                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
647                         /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
648                         if (mstrip == NULL) {
649                                 /* add a new meta-strip, and add it before the current strip that it will replace... */
650                                 mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
651                                 mstrip->type = NLASTRIP_TYPE_META;
652                                 BLI_insertlinkbefore(strips, strip, mstrip);
653                                 
654                                 /* set flags */
655                                 mstrip->flag = NLASTRIP_FLAG_SELECT;
656                                 
657                                 /* set temp flag if appropriate (i.e. for transform-type editing) */
658                                 if (temp)
659                                         mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
660                                         
661                                 /* set default repeat/scale values to prevent warnings */
662                                 mstrip->repeat= mstrip->scale= 1.0f;
663                                 
664                                 /* make its start frame be set to the start frame of the current strip */
665                                 mstrip->start= strip->start;
666                         }
667                         
668                         /* remove the selected strips from the track, and add to the meta */
669                         BLI_remlink(strips, strip);
670                         BLI_addtail(&mstrip->strips, strip);
671                         
672                         /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
673                         mstrip->end= strip->end;
674                 }
675                 else {
676                         /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
677                          * so stop adding strips to the current meta
678                          */
679                         mstrip= NULL;
680                 }
681         }
682 }
683
684 /* Split a meta-strip into a set of normal strips */
685 void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip)
686 {
687         NlaStrip *cs, *csn;
688         
689         /* sanity check */
690         if ELEM(NULL, strips, strip)
691                 return;
692         
693         /* move each one of the meta-strip's children before the meta-strip
694          * in the list of strips after unlinking them from the meta-strip
695          */
696         for (cs= strip->strips.first; cs; cs= csn) {
697                 csn= cs->next;
698                 BLI_remlink(&strip->strips, cs);
699                 BLI_insertlinkbefore(strips, strip, cs);
700         }
701         
702         /* free the meta-strip now */
703         BLI_freelinkN(strips, strip);
704 }
705
706 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
707  *      sel: only consider selected meta-strips, otherwise all meta-strips are removed
708  *      onlyTemp: only remove the 'temporary' meta-strips used for transforms
709  */
710 void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp)
711 {
712         NlaStrip *strip, *stripn;
713         
714         /* sanity checks */
715         if ELEM(NULL, strips, strips->first)
716                 return;
717         
718         /* remove meta-strips fitting the criteria of the arguments */
719         for (strip= strips->first; strip; strip= stripn) {
720                 stripn= strip->next;
721                 
722                 /* check if strip is a meta-strip */
723                 if (strip->type == NLASTRIP_TYPE_META) {
724                         /* if check if selection and 'temporary-only' considerations are met */
725                         if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
726                                 if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
727                                         BKE_nlastrips_clear_metastrip(strips, strip);
728                                 }
729                         }
730                 }
731         }
732 }
733
734 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the
735  * strip isn't attached to anyy list of strips 
736  */
737 short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip)
738 {
739         /* sanity checks */
740         if ELEM(NULL, mstrip, strip)
741                 return 0;
742                 
743         /* firstly, check if the meta-strip has space for this */
744         if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
745                 return 0;
746                 
747         /* check if this would need to be added to the ends of the meta,
748          * and subsequently, if the neighbouring strips allow us enough room
749          */
750         if (strip->start < mstrip->start) {
751                 /* check if strip to the left (if it exists) ends before the 
752                  * start of the strip we're trying to add 
753                  */
754                 if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
755                         /* add strip to start of meta's list, and expand dimensions */
756                         BLI_addhead(&mstrip->strips, strip);
757                         mstrip->start= strip->start;
758                         
759                         return 1;
760                 }
761                 else /* failed... no room before */
762                         return 0;
763         }
764         else if (strip->end > mstrip->end) {
765                 /* check if strip to the right (if it exists) starts before the 
766                  * end of the strip we're trying to add 
767                  */
768                 if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
769                         /* add strip to end of meta's list, and expand dimensions */
770                         BLI_addtail(&mstrip->strips, strip);
771                         mstrip->end= strip->end;
772                         
773                         return 1;
774                 }
775                 else /* failed... no room after */
776                         return 0;
777         }
778         else {
779                 /* just try to add to the meta-strip (no dimension changes needed) */
780                 return BKE_nlastrips_add_strip(&mstrip->strips, strip);
781         }
782 }
783
784 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively), 
785  * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
786  */
787 void BKE_nlameta_flush_transforms (NlaStrip *mstrip) 
788 {
789         NlaStrip *strip;
790         float oStart, oEnd, offset;
791         float oLen, nLen;
792         short scaleChanged= 0;
793         
794         /* sanity checks 
795          *      - strip must exist
796          *      - strip must be a meta-strip with some contents
797          */
798         if ELEM(NULL, mstrip, mstrip->strips.first)
799                 return;
800         if (mstrip->type != NLASTRIP_TYPE_META)
801                 return;
802                 
803         /* get the original start/end points, and calculate the start-frame offset
804          *      - these are simply the start/end frames of the child strips, 
805          *        since we assume they weren't transformed yet
806          */
807         oStart= ((NlaStrip *)mstrip->strips.first)->start;
808         oEnd= ((NlaStrip *)mstrip->strips.last)->end;
809         offset= mstrip->start - oStart;
810         
811         /* optimisation:
812          * don't flush if nothing changed yet
813          *      TODO: maybe we need a flag to say always flush?
814          */
815         if (IS_EQ(oStart, mstrip->start) && IS_EQ(oEnd, mstrip->end))
816                 return;
817         
818         /* check if scale changed */
819         oLen = oEnd - oStart;
820         nLen = mstrip->end - mstrip->start;
821         if (IS_EQ(nLen, oLen) == 0)
822                 scaleChanged= 1;
823         
824         /* for each child-strip, calculate new start/end points based on this new info */
825         for (strip= mstrip->strips.first; strip; strip= strip->next) {
826                 if (scaleChanged) {
827                         PointerRNA ptr;
828                         float p1, p2, nStart, nEnd;
829                         
830                         /* compute positions of endpoints relative to old extents of strip */
831                         p1= (strip->start - oStart) / oLen;
832                         p2= (strip->end - oStart) / oLen;
833                         
834                         /* compute the new strip endpoints using the proportions */
835                         nStart= (p1 * nLen) + mstrip->start;
836                         nEnd= (p2 * nLen) + mstrip->start;
837                         
838                         /* firstly, apply the new positions manually, then apply using RNA 
839                          *      - first time is to make sure no truncation errors from one endpoint not being 
840                          *        set yet occur
841                          *      - second time is to make sure scale is computed properly...
842                          */
843                         strip->start= nStart;
844                         strip->end= nEnd;
845                         
846                         RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
847                         RNA_float_set(&ptr, "start_frame", nStart);
848                         RNA_float_set(&ptr, "end_frame", nEnd);
849                 }
850                 else {
851                         /* just apply the changes in offset to both ends of the strip */
852                         strip->start += offset;
853                         strip->end += offset;
854                 }
855                 
856                 /* finally, make sure the strip's children (if it is a meta-itself), get updated */
857                 BKE_nlameta_flush_transforms(strip);
858         }
859 }
860
861 /* NLA-Tracks ---------------------------------------- */
862
863 /* Find the active NLA-track for the given stack */
864 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
865 {
866         NlaTrack *nlt;
867         
868         /* sanity check */
869         if ELEM(NULL, tracks, tracks->first)
870                 return NULL;
871                 
872         /* try to find the first active track */
873         for (nlt= tracks->first; nlt; nlt= nlt->next) {
874                 if (nlt->flag & NLATRACK_ACTIVE)
875                         return nlt;
876         }
877         
878         /* none found */
879         return NULL;
880 }
881
882 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
883  * that has this status in its AnimData block.
884  */
885 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
886 {
887         NlaTrack *nt;
888         
889         /* sanity check */
890         if ELEM(NULL, adt, adt->nla_tracks.first)
891                 return;
892                 
893         /* firstly, make sure 'solo' flag for all tracks is disabled */
894         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
895                 if (nt != nlt)
896                         nt->flag &= ~NLATRACK_SOLO;
897         }
898                 
899         /* now, enable 'solo' for the given track if appropriate */
900         if (nlt) {
901                 /* toggle solo status */
902                 nlt->flag ^= NLATRACK_SOLO;
903                 
904                 /* set or clear solo-status on AnimData */
905                 if (nlt->flag & NLATRACK_SOLO)
906                         adt->flag |= ADT_NLA_SOLO_TRACK;
907                 else
908                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
909         }
910         else
911                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
912 }
913
914 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
915  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
916  */
917 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
918 {
919         NlaTrack *nlt;
920         
921         /* sanity check */
922         if ELEM(NULL, tracks, tracks->first)
923                 return;
924         
925         /* deactive all the rest */
926         for (nlt= tracks->first; nlt; nlt= nlt->next) 
927                 nlt->flag &= ~NLATRACK_ACTIVE;
928                 
929         /* set the given one as the active one */
930         if (nlt_a)
931                 nlt_a->flag |= NLATRACK_ACTIVE;
932 }
933
934 /* Check if there is any space in the given track to add a strip of the given length */
935 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
936 {
937         /* sanity checks */
938         if ((nlt == NULL) || IS_EQ(start, end))
939                 return 0;
940         if (start > end) {
941                 puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
942                 SWAP(float, start, end);
943         }
944         
945         /* check if there's any space left in the track for a strip of the given length */
946         return BKE_nlastrips_has_space(&nlt->strips, start, end);
947 }
948
949 /* Rearrange the strips in the track so that they are always in order 
950  * (usually only needed after a strip has been moved) 
951  */
952 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
953 {
954         /* sanity checks */
955         if ELEM(NULL, nlt, nlt->strips.first)
956                 return;
957         
958         /* sort the strips with a more generic function */
959         BKE_nlastrips_sort_strips(&nlt->strips);
960 }
961
962 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
963  * isn't currently attached to another one 
964  */
965 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
966 {
967         /* sanity checks */
968         if ELEM(NULL, nlt, strip)
969                 return 0;
970                 
971         /* try to add the strip to the track using a more generic function */
972         return BKE_nlastrips_add_strip(&nlt->strips, strip);
973 }
974
975 /* NLA Strips -------------------------------------- */
976
977 /* Find the active NLA-strip within the given track */
978 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
979 {
980         NlaStrip *strip;
981         
982         /* sanity check */
983         if ELEM(NULL, nlt, nlt->strips.first)
984                 return NULL;
985                 
986         /* try to find the first active strip */
987         for (strip= nlt->strips.first; strip; strip= strip->next) {
988                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
989                         return strip;
990         }
991         
992         /* none found */
993         return NULL;
994 }
995
996 /* Does the given NLA-strip fall within the given bounds (times)? */
997 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
998 {
999         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
1000         const float boundsLen= (float)fabs(max - min);
1001         
1002         /* sanity checks */
1003         if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f))
1004                 return 0;
1005         
1006         /* only ok if at least part of the strip is within the bounding window
1007          *      - first 2 cases cover when the strip length is less than the bounding area
1008          *      - second 2 cases cover when the strip length is greater than the bounding area
1009          */
1010         if ( (stripLen < boundsLen) && 
1011                  !(IN_RANGE(strip->start, min, max) ||
1012                    IN_RANGE(strip->end, min, max)) )
1013         {
1014                 return 0;
1015         }
1016         if ( (stripLen > boundsLen) && 
1017                  !(IN_RANGE(min, strip->start, strip->end) ||
1018                    IN_RANGE(max, strip->start, strip->end)) )
1019         {
1020                 return 0;
1021         }
1022         
1023         /* should be ok! */
1024         return 1;
1025 }
1026
1027 /* Is the given NLA-strip the first one to occur for the given AnimData block */
1028 // TODO: make this an api method if necesary, but need to add prefix first
1029 short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
1030 {
1031         NlaTrack *nlt;
1032         NlaStrip *ns;
1033         
1034         /* sanity checks */
1035         if ELEM(NULL, adt, strip)
1036                 return 0;
1037                 
1038         /* check if strip has any strips before it */
1039         if (strip->prev)
1040                 return 0;
1041                 
1042         /* check other tracks to see if they have a strip that's earlier */
1043         // TODO: or should we check that the strip's track is also the first?
1044         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1045                 /* only check the first strip, assuming that they're all in order */
1046                 ns= nlt->strips.first;
1047                 if (ns) {
1048                         if (ns->start < strip->start)
1049                                 return 0;
1050                 }
1051         }       
1052         
1053         /* should be first now */
1054         return 1;
1055 }
1056
1057 /* Animated Strips ------------------------------------------- */
1058
1059 /* Check if the given NLA-Track has any strips with own F-Curves */
1060 short BKE_nlatrack_has_animated_strips (NlaTrack *nlt)
1061 {
1062         NlaStrip *strip;
1063         
1064         /* sanity checks */
1065         if ELEM(NULL, nlt, nlt->strips.first)
1066                 return 0;
1067                 
1068         /* check each strip for F-Curves only (don't care about whether the flags are set) */
1069         for (strip= nlt->strips.first; strip; strip= strip->next) {
1070                 if (strip->fcurves.first)
1071                         return 1;
1072         }
1073         
1074         /* none found */
1075         return 0;
1076 }
1077
1078 /* Check if given NLA-Tracks have any strips with own F-Curves */
1079 short BKE_nlatracks_have_animated_strips (ListBase *tracks)
1080 {
1081         NlaTrack *nlt;
1082         
1083         /* sanity checks */
1084         if ELEM(NULL, tracks, tracks->first)
1085                 return 0;
1086                 
1087         /* check each track, stopping on the first hit */
1088         for (nlt= tracks->first; nlt; nlt= nlt->next) {
1089                 if (BKE_nlatrack_has_animated_strips(nlt))
1090                         return 1;
1091         }
1092         
1093         /* none found */
1094         return 0;
1095 }
1096
1097 /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
1098 void BKE_nlastrip_validate_fcurves (NlaStrip *strip) 
1099 {
1100         FCurve *fcu;
1101         
1102         /* sanity checks */
1103         if (strip == NULL)
1104                 return;
1105         
1106         /* if controlling influence... */
1107         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
1108                 /* try to get F-Curve */
1109                 fcu= list_find_fcurve(&strip->fcurves, "influence", 0);
1110                 
1111                 /* add one if not found */
1112                 if (fcu == NULL) {
1113                         /* make new F-Curve */
1114                         fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
1115                         BLI_addtail(&strip->fcurves, fcu);
1116                         
1117                         /* set default flags */
1118                         fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
1119                         
1120                         /* store path - make copy, and store that */
1121                         fcu->rna_path= BLI_strdupn("influence", 9);
1122                         
1123                         // TODO: insert a few keyframes to ensure default behaviour?
1124                 }
1125         }
1126         
1127         /* if controlling time... */
1128         if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
1129                 /* try to get F-Curve */
1130                 fcu= list_find_fcurve(&strip->fcurves, "strip_time", 0);
1131                 
1132                 /* add one if not found */
1133                 if (fcu == NULL) {
1134                         /* make new F-Curve */
1135                         fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
1136                         BLI_addtail(&strip->fcurves, fcu);
1137                         
1138                         /* set default flags */
1139                         fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
1140                         
1141                         /* store path - make copy, and store that */
1142                         fcu->rna_path= BLI_strdupn("strip_time", 10);
1143                         
1144                         // TODO: insert a few keyframes to ensure default behaviour?
1145                 }
1146         }
1147 }
1148
1149 /* Sanity Validation ------------------------------------ */
1150
1151 /* Find (and set) a unique name for a strip from the whole AnimData block 
1152  * Uses a similar method to the BLI method, but is implemented differently
1153  * as we need to ensure that the name is unique over several lists of tracks,
1154  * not just a single track.
1155  */
1156 void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip)
1157 {
1158         GHash *gh;
1159         NlaStrip *tstrip;
1160         NlaTrack *nlt;
1161         
1162         /* sanity checks */
1163         if ELEM(NULL, adt, strip)
1164                 return;
1165                 
1166         /* give strip a default name if none already */
1167         if (strip->name[0]==0) {
1168                 switch (strip->type) {
1169                         case NLASTRIP_TYPE_CLIP: /* act-clip */
1170                                 sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>"));
1171                                 break;
1172                         case NLASTRIP_TYPE_TRANSITION: /* transition */
1173                                 sprintf(strip->name, "Transition");
1174                                 break;
1175                         case NLASTRIP_TYPE_META: /* meta */
1176                                 sprintf(strip->name, "Meta");
1177                                 break;
1178                         default:
1179                                 sprintf(strip->name, "NLA Strip");
1180                                 break;
1181                 }
1182         }
1183         
1184         /* build a hash-table of all the strips in the tracks 
1185          *      - this is easier than iterating over all the tracks+strips hierarchy everytime
1186          *        (and probably faster)
1187          */
1188         gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp);
1189         
1190         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1191                 for (tstrip= nlt->strips.first; tstrip; tstrip= tstrip->next) {
1192                         /* don't add the strip of interest */
1193                         if (tstrip == strip) 
1194                                 continue;
1195                         
1196                         /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
1197                         BLI_ghash_insert(gh, tstrip->name, tstrip);
1198                 }
1199         }
1200         
1201         /* if the hash-table has a match for this name, try other names... 
1202          *      - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
1203          */
1204         if (BLI_ghash_haskey(gh, strip->name)) {
1205                 char tempname[128];
1206                 int     number = 1;
1207                 char *dot;
1208                 
1209                 /* Strip off the suffix */
1210                 dot = strchr(strip->name, '.');
1211                 if (dot) *dot=0;
1212                 
1213                 /* Try different possibilities */
1214                 for (number = 1; number <= 999; number++) {
1215                         /* assemble alternative name */
1216                         BLI_snprintf(tempname, 128, "%s%c%03d", strip->name, ".", number);
1217                         
1218                         /* if hash doesn't have this, set it */
1219                         if (BLI_ghash_haskey(gh, tempname) == 0) {
1220                                 BLI_strncpy(strip->name, tempname, sizeof(strip->name));
1221                                 break;
1222                         }
1223                 }
1224         }
1225         
1226         /* free the hash... */
1227         BLI_ghash_free(gh, NULL, NULL);
1228 }
1229
1230 /* ---- */
1231
1232 /* Determine auto-blending for the given strip */
1233 void BKE_nlastrip_validate_autoblends (NlaTrack *nlt, NlaStrip *nls)
1234 {
1235         NlaTrack *track;
1236         NlaStrip *strip;
1237         //float *ps=NULL, *pe=NULL;
1238         //float *ns=NULL, *ne=NULL;
1239         
1240         /* sanity checks */
1241         if ELEM(NULL, nls, nlt)
1242                 return;
1243         if ((nlt->prev == NULL) && (nlt->next == NULL))
1244                 return;
1245         if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS)==0)
1246                 return;
1247         
1248         /* get test ranges */
1249         if (nlt->prev) {
1250                 /* find strips that overlap over the start/end of the given strip,
1251                  * but which don't cover the entire length 
1252                  */
1253                 track= nlt->prev;
1254                 for (strip= track->strips.first; strip; strip= strip->next) {
1255                         
1256                 }
1257         }
1258         if (nlt->next) {
1259                 /* find strips that overlap over the start/end of the given strip,
1260                  * but which don't cover the entire length 
1261                  */
1262                 track= nlt->next;
1263                 for (strip= track->strips.first; strip; strip= strip->next) {
1264                         
1265                 }
1266         }
1267 }
1268
1269 /* Ensure that auto-blending and other settings are set correctly */
1270 void BKE_nla_validate_state (AnimData *adt)
1271 {
1272         NlaStrip *strip;
1273         NlaTrack *nlt;
1274         
1275         /* sanity checks */
1276         if ELEM(NULL, adt, adt->nla_tracks.first)
1277                 return;
1278                 
1279         /* adjust blending values for auto-blending */
1280         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1281                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1282                         BKE_nlastrip_validate_autoblends(nlt, strip);
1283                 }
1284         }
1285 }
1286
1287 /* Core Tools ------------------------------------------- */
1288
1289 /* For the given AnimData block, add the active action to the NLA
1290  * stack (i.e. 'push-down' action). The UI should only allow this 
1291  * for normal editing only (i.e. not in editmode for some strip's action),
1292  * so no checks for this are performed.
1293  */
1294 // TODO: maybe we should have checks for this too...
1295 void BKE_nla_action_pushdown (AnimData *adt)
1296 {
1297         NlaStrip *strip;
1298         
1299         /* sanity checks */
1300         // TODO: need to report the error for this
1301         if ELEM(NULL, adt, adt->action) 
1302                 return;
1303                 
1304         /* if the action is empty, we also shouldn't try to add to stack, 
1305          * as that will cause us grief down the track
1306          */
1307         // TODO: what about modifiers?
1308         if (action_has_motion(adt->action) == 0) {
1309                 printf("BKE_nla_action_pushdown(): action has no data \n");
1310                 return;
1311         }
1312         
1313         /* add a new NLA strip to the track, which references the active action */
1314         strip= add_nlastrip_to_stack(adt, adt->action);
1315         
1316         /* do other necessary work on strip */  
1317         if (strip) {
1318                 /* clear reference to action now that we've pushed it onto the stack */
1319                 adt->action->id.us--;
1320                 adt->action= NULL;
1321                 
1322                 /* if the strip is the first one in the track it lives in, check if there
1323                  * are strips in any other tracks that may be before this, and set the extend
1324                  * mode accordingly
1325                  */
1326                 if (nlastrip_is_first(adt, strip) == 0) {
1327                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
1328                          * so that it doesn't override strips in previous tracks
1329                          */
1330                         // FIXME: this needs to be more automated, since user can rearrange strips
1331                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
1332                 }
1333         }
1334 }
1335
1336
1337 /* Find the active strip + track combo, and set them up as the tweaking track,
1338  * and return if successful or not.
1339  */
1340 short BKE_nla_tweakmode_enter (AnimData *adt)
1341 {
1342         NlaTrack *nlt, *activeTrack=NULL;
1343         NlaStrip *strip, *activeStrip=NULL;
1344         
1345         /* verify that data is valid */
1346         if ELEM(NULL, adt, adt->nla_tracks.first)
1347                 return 0;
1348                 
1349         /* if block is already in tweakmode, just leave, but we should report 
1350          * that this block is in tweakmode (as our returncode)
1351          */
1352         if (adt->flag & ADT_NLA_EDIT_ON)
1353                 return 1;
1354                 
1355         /* go over the tracks, finding the active one, and its active strip
1356          *      - if we cannot find both, then there's nothing to do
1357          */
1358         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1359                 /* check if active */
1360                 if (nlt->flag & NLATRACK_ACTIVE) {
1361                         /* store reference to this active track */
1362                         activeTrack= nlt;
1363                         
1364                         /* now try to find active strip */
1365                         activeStrip= BKE_nlastrip_find_active(nlt);
1366                         break;
1367                 }       
1368         }
1369         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
1370                 printf("NLA tweakmode enter - neither active requirement found \n");
1371                 return 0;
1372         }
1373                 
1374         /* go over all the tracks up to the active one, tagging each strip that uses the same 
1375          * action as the active strip, but leaving everything else alone
1376          */
1377         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
1378                 for (strip= nlt->strips.first; strip; strip= strip->next) {
1379                         if (strip->act == activeStrip->act)
1380                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
1381                         else
1382                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
1383                 }
1384         }
1385         
1386         
1387         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
1388          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
1389          */
1390         for (nlt= activeTrack; nlt; nlt= nlt->next)
1391                 nlt->flag |= NLATRACK_DISABLED;
1392         
1393         /* handle AnimData level changes:
1394          *      - 'real' active action to temp storage (no need to change user-counts)
1395          *      - action of active strip set to be the 'active action', and have its usercount incremented
1396          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
1397          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
1398          */
1399         adt->tmpact= adt->action;
1400         adt->action= activeStrip->act;
1401         adt->actstrip= activeStrip;
1402         id_us_plus(&activeStrip->act->id);
1403         adt->flag |= ADT_NLA_EDIT_ON;
1404         
1405         /* done! */
1406         return 1;
1407 }
1408
1409 /* Exit tweakmode for this AnimData block */
1410 void BKE_nla_tweakmode_exit (AnimData *adt)
1411 {
1412         NlaStrip *strip;
1413         NlaTrack *nlt;
1414         
1415         /* verify that data is valid */
1416         if ELEM(NULL, adt, adt->nla_tracks.first)
1417                 return;
1418                 
1419         /* hopefully the flag is correct - skip if not on */
1420         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
1421                 return;
1422                 
1423         // TODO: need to sync the user-strip with the new state of the action!
1424                 
1425         /* for all Tracks, clear the 'disabled' flag
1426          * for all Strips, clear the 'tweak-user' flag
1427          */
1428         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
1429                 nlt->flag &= ~NLATRACK_DISABLED;
1430                 
1431                 for (strip= nlt->strips.first; strip; strip= strip->next) 
1432                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
1433         }
1434         
1435         /* handle AnimData level changes:
1436          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
1437          *      - 'real' active action is restored from storage
1438          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
1439          *      - editing-flag for this AnimData block should also get turned off
1440          *      - clear pointer to active strip
1441          */
1442         if (adt->action) adt->action->id.us--;
1443         adt->action= adt->tmpact;
1444         adt->tmpact= NULL;
1445         adt->actstrip= NULL;
1446         adt->flag &= ~ADT_NLA_EDIT_ON;
1447 }
1448
1449 /* *************************************************** */