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