Blender  V2.59
nla.c
Go to the documentation of this file.
00001 /*
00002  * $Id: nla.c 35836 2011-03-28 04:22:50Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Joshua Leung (full recode)
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <stdlib.h>
00036 #include <stddef.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <math.h>
00040 #include <float.h>
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "BLI_utildefines.h"
00045 #include "BLI_ghash.h"
00046 
00047 #include "DNA_anim_types.h"
00048 #include "DNA_scene_types.h"
00049 
00050 #include "BKE_action.h"
00051 #include "BKE_fcurve.h"
00052 #include "BKE_nla.h"
00053 #include "BKE_global.h"
00054 #include "BKE_library.h"
00055 
00056 
00057 #include "RNA_access.h"
00058 #include "nla_private.h"
00059 
00060 
00061 
00062 /* *************************************************** */
00063 /* Data Management */
00064 
00065 /* Freeing ------------------------------------------- */
00066 
00067 /* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
00068  * and the strip itself. 
00069  */
00070 void free_nlastrip (ListBase *strips, NlaStrip *strip)
00071 {
00072         NlaStrip *cs, *csn;
00073         
00074         /* sanity checks */
00075         if (strip == NULL)
00076                 return;
00077                 
00078         /* free child-strips */
00079         for (cs= strip->strips.first; cs; cs= csn) {
00080                 csn= cs->next;
00081                 free_nlastrip(&strip->strips, cs);
00082         }
00083                 
00084         /* remove reference to action */
00085         if (strip->act)
00086                 id_us_min(&strip->act->id);
00087                 
00088         /* free remapping info */
00089         //if (strip->remap)
00090         //      BKE_animremap_free();
00091         
00092         /* free own F-Curves */
00093         free_fcurves(&strip->fcurves);
00094         
00095         /* free own F-Modifiers */
00096         free_fmodifiers(&strip->modifiers);
00097         
00098         /* free the strip itself */
00099         if (strips)
00100                 BLI_freelinkN(strips, strip);
00101         else
00102                 MEM_freeN(strip);
00103 }
00104 
00105 /* Remove the given NLA track from the set of NLA tracks, free the track's data,
00106  * and the track itself.
00107  */
00108 void free_nlatrack (ListBase *tracks, NlaTrack *nlt)
00109 {
00110         NlaStrip *strip, *stripn;
00111         
00112         /* sanity checks */
00113         if (nlt == NULL)
00114                 return;
00115                 
00116         /* free strips */
00117         for (strip= nlt->strips.first; strip; strip= stripn) {
00118                 stripn= strip->next;
00119                 free_nlastrip(&nlt->strips, strip);
00120         }
00121         
00122         /* free NLA track itself now */
00123         if (tracks)
00124                 BLI_freelinkN(tracks, nlt);
00125         else
00126                 MEM_freeN(nlt);
00127 }
00128 
00129 /* Free the elements of type NLA Tracks provided in the given list, but do not free
00130  * the list itself since that is not free-standing
00131  */
00132 void free_nladata (ListBase *tracks)
00133 {
00134         NlaTrack *nlt, *nltn;
00135         
00136         /* sanity checks */
00137         if ELEM(NULL, tracks, tracks->first)
00138                 return;
00139                 
00140         /* free tracks one by one */
00141         for (nlt= tracks->first; nlt; nlt= nltn) {
00142                 nltn= nlt->next;
00143                 free_nlatrack(tracks, nlt);
00144         }
00145         
00146         /* clear the list's pointers to be safe */
00147         tracks->first= tracks->last= NULL;
00148 }
00149 
00150 /* Copying ------------------------------------------- */
00151 
00152 /* Copy NLA strip */
00153 NlaStrip *copy_nlastrip (NlaStrip *strip)
00154 {
00155         NlaStrip *strip_d;
00156         NlaStrip *cs, *cs_d;
00157         
00158         /* sanity check */
00159         if (strip == NULL)
00160                 return NULL;
00161                 
00162         /* make a copy */
00163         strip_d= MEM_dupallocN(strip);
00164         strip_d->next= strip_d->prev= NULL;
00165         
00166         /* increase user-count of action */
00167         if (strip_d->act)
00168                 id_us_plus(&strip_d->act->id);
00169                 
00170         /* copy F-Curves and modifiers */
00171         copy_fcurves(&strip_d->fcurves, &strip->fcurves);
00172         copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
00173         
00174         /* make a copy of all the child-strips, one at a time */
00175         strip_d->strips.first= strip_d->strips.last= NULL;
00176         
00177         for (cs= strip->strips.first; cs; cs= cs->next) {
00178                 cs_d= copy_nlastrip(cs);
00179                 BLI_addtail(&strip_d->strips, cs_d);
00180         }
00181         
00182         /* return the strip */
00183         return strip_d;
00184 }
00185 
00186 /* Copy NLA Track */
00187 NlaTrack *copy_nlatrack (NlaTrack *nlt)
00188 {
00189         NlaStrip *strip, *strip_d;
00190         NlaTrack *nlt_d;
00191         
00192         /* sanity check */
00193         if (nlt == NULL)
00194                 return NULL;
00195                 
00196         /* make a copy */
00197         nlt_d= MEM_dupallocN(nlt);
00198         nlt_d->next= nlt_d->prev= NULL;
00199         
00200         /* make a copy of all the strips, one at a time */
00201         nlt_d->strips.first= nlt_d->strips.last= NULL;
00202         
00203         for (strip= nlt->strips.first; strip; strip= strip->next) {
00204                 strip_d= copy_nlastrip(strip);
00205                 BLI_addtail(&nlt_d->strips, strip_d);
00206         }
00207         
00208         /* return the copy */
00209         return nlt_d;
00210 }
00211 
00212 /* Copy all NLA data */
00213 void copy_nladata (ListBase *dst, ListBase *src)
00214 {
00215         NlaTrack *nlt, *nlt_d;
00216         
00217         /* sanity checks */
00218         if ELEM(NULL, dst, src)
00219                 return;
00220                 
00221         /* clear out the destination list first for precautions... */
00222         dst->first= dst->last= NULL;
00223                 
00224         /* copy each NLA-track, one at a time */
00225         for (nlt= src->first; nlt; nlt= nlt->next) {
00226                 /* make a copy, and add the copy to the destination list */
00227                 nlt_d= copy_nlatrack(nlt);
00228                 BLI_addtail(dst, nlt_d);
00229         }
00230 }
00231 
00232 /* Adding ------------------------------------------- */
00233 
00234 /* Add a NLA Track to the given AnimData 
00235  *      - prev: NLA-Track to add the new one after
00236  */
00237 NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev)
00238 {
00239         NlaTrack *nlt;
00240         
00241         /* sanity checks */
00242         if (adt == NULL)
00243                 return NULL;
00244                 
00245         /* allocate new track */
00246         nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack");
00247         
00248         /* set settings requiring the track to not be part of the stack yet */
00249         nlt->flag = NLATRACK_SELECTED;
00250         nlt->index= BLI_countlist(&adt->nla_tracks);
00251         
00252         /* add track to stack, and make it the active one */
00253         if (prev)
00254                 BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
00255         else
00256                 BLI_addtail(&adt->nla_tracks, nlt);
00257         BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
00258         
00259         /* must have unique name, but we need to seed this */
00260         strcpy(nlt->name, "NlaTrack");
00261         BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), sizeof(nlt->name));
00262         
00263         /* return the new track */
00264         return nlt;
00265 }
00266 
00267 /* Add a NLA Strip referencing the given Action */
00268 NlaStrip *add_nlastrip (bAction *act)
00269 {
00270         NlaStrip *strip;
00271         
00272         /* sanity checks */
00273         if (act == NULL)
00274                 return NULL;
00275                 
00276         /* allocate new strip */
00277         strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
00278         
00279         /* generic settings 
00280          *      - selected flag to highlight this to the user
00281          *      - auto-blends to ensure that blend in/out values are automatically 
00282          *        determined by overlaps of strips
00283          *      - (XXX) synchronisation of strip-length in accordance with changes to action-length
00284          *        is not done though, since this should only really happens in editmode for strips now
00285          *        though this decision is still subject to further review...
00286          */
00287         strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
00288         
00289         /* assign the action reference */
00290         strip->act= act;
00291         id_us_plus(&act->id);
00292         
00293         /* determine initial range 
00294          *      - strip length cannot be 0... ever...
00295          */
00296         calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
00297         
00298         strip->start = strip->actstart;
00299         strip->end = (IS_EQF(strip->actstart, strip->actend)) ?  (strip->actstart + 1.0f): (strip->actend);
00300         
00301         /* strip should be referenced as-is */
00302         strip->scale= 1.0f;
00303         strip->repeat = 1.0f;
00304         
00305         /* return the new strip */
00306         return strip;
00307 }
00308 
00309 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
00310 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
00311 {
00312         NlaStrip *strip;
00313         NlaTrack *nlt;
00314         
00315         /* sanity checks */
00316         if ELEM(NULL, adt, act)
00317                 return NULL;
00318         
00319         /* create a new NLA strip */
00320         strip= add_nlastrip(act);
00321         if (strip == NULL)
00322                 return NULL;
00323         
00324         /* firstly try adding strip to last track, but if that fails, add to a new track */
00325         if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
00326                 /* trying to add to the last track failed (no track or no space), 
00327                  * so add a new track to the stack, and add to that...
00328                  */
00329                 nlt= add_nlatrack(adt, NULL);
00330                 BKE_nlatrack_add_strip(nlt, strip);
00331         }
00332         
00333         /* automatically name it too */
00334         BKE_nlastrip_validate_name(adt, strip);
00335         
00336         /* returns the strip added */
00337         return strip;
00338 }
00339 
00340 /* *************************************************** */
00341 /* NLA Evaluation <-> Editing Stuff */
00342 
00343 /* Strip Mapping ------------------------------------- */
00344 
00345 /* non clipped mapping for strip-time <-> global time (for Action-Clips)
00346  *      invert = convert action-strip time to global time 
00347  */
00348 static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode)
00349 {
00350         float actlength, scale;
00351         // float repeat; // UNUSED
00352         
00353         /* get number of repeats */
00354         if (IS_EQF(strip->repeat, 0.0f)) strip->repeat = 1.0f;
00355         // repeat = strip->repeat; // UNUSED
00356         
00357         /* scaling */
00358         if (IS_EQF(strip->scale, 0.0f)) strip->scale= 1.0f;
00359         scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */
00360         
00361         /* length of referenced action */
00362         actlength = strip->actend - strip->actstart;
00363         if (IS_EQF(actlength, 0.0f)) actlength = 1.0f;
00364         
00365         /* reversed = play strip backwards */
00366         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
00367                 // FIXME: this won't work right with Graph Editor?
00368                 if (mode == NLATIME_CONVERT_MAP) {
00369                         return strip->end - scale*(cframe - strip->actstart);
00370                 }
00371                 else if (mode == NLATIME_CONVERT_UNMAP) {
00372                         return (strip->end + (strip->actstart * scale - cframe)) / scale;
00373                 }
00374                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
00375                         if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) {
00376                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
00377                                  * by catching the case where repeats is a whole number, which means that the end of the strip
00378                                  * could also be interpreted as the end of the start of a repeat
00379                                  */
00380                                 return strip->actstart;
00381                         }
00382                         else {
00383                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
00384                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
00385                                  */
00386                                 return strip->actend - fmodf(cframe - strip->start, actlength*scale) / scale;
00387                         }
00388                 }
00389         }
00390         else {
00391                 if (mode == NLATIME_CONVERT_MAP) {
00392                         return strip->start + scale*(cframe - strip->actstart);
00393                 }
00394                 else if (mode == NLATIME_CONVERT_UNMAP) {
00395                         return strip->actstart + (cframe - strip->start) / scale;
00396                 }
00397                 else /* if (mode == NLATIME_CONVERT_EVAL) */{
00398                         if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) {
00399                                 /* this case prevents the motion snapping back to the first frame at the end of the strip 
00400                                  * by catching the case where repeats is a whole number, which means that the end of the strip
00401                                  * could also be interpreted as the end of the start of a repeat
00402                                  */
00403                                 return strip->actend;
00404                         }
00405                         else {
00406                                 /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working
00407                                  * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
00408                                  */
00409                                 return strip->actstart + fmodf(cframe - strip->start, actlength*scale) / scale;
00410                         }
00411                 }
00412         }
00413 }
00414 
00415 /* non clipped mapping for strip-time <-> global time (for Transitions)
00416  *      invert = convert action-strip time to global time 
00417  */
00418 static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode)
00419 {
00420         float length;
00421         
00422         /* length of strip */
00423         length= strip->end - strip->start;
00424         
00425         /* reversed = play strip backwards */
00426         if (strip->flag & NLASTRIP_FLAG_REVERSE) {
00427                 if (mode == NLATIME_CONVERT_MAP)
00428                         return strip->end - (length * cframe);
00429                 else
00430                         return (strip->end - cframe) / length;
00431         }
00432         else {
00433                 if (mode == NLATIME_CONVERT_MAP)
00434                         return (length * cframe) + strip->start;
00435                 else
00436                         return (cframe - strip->start) / length;
00437         }
00438 }
00439 
00440 /* non clipped mapping for strip-time <-> global time
00441  *      mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
00442  *
00443  * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
00444  * but should not be directly relied on for stuff which interacts with editors
00445  */
00446 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
00447 {
00448         switch (strip->type) {
00449                 case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
00450                 case NLASTRIP_TYPE_TRANSITION: /* transition */
00451                         return nlastrip_get_frame_transition(strip, cframe, mode);
00452                 
00453                 case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
00454                 default:
00455                         return nlastrip_get_frame_actionclip(strip, cframe, mode);
00456         }       
00457 }
00458 
00459 
00460 /* Non clipped mapping for strip-time <-> global time
00461  *      mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_*
00462  *
00463  * Public API method - perform this mapping using the given AnimData block
00464  * and perform any necessary sanity checks on the value
00465  */
00466 float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
00467 {
00468         NlaStrip *strip;
00469         
00470         /* sanity checks 
00471          *      - obviously we've got to have some starting data
00472          *      - when not in tweakmode, the active Action does not have any scaling applied :)
00473          *      - when in tweakmode, if the no-mapping flag is set, do not map
00474          */
00475         if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
00476                 return cframe;
00477                 
00478         /* if the active-strip info has been stored already, access this, otherwise look this up
00479          * and store for (very probable) future usage
00480          */
00481         if (adt->actstrip == NULL) {
00482                 NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks);
00483                 adt->actstrip= BKE_nlastrip_find_active(nlt);
00484         }
00485         strip= adt->actstrip;
00486         
00487         /* sanity checks 
00488          *      - in rare cases, we may not be able to find this strip for some reason (internal error)
00489          *      - for now, if the user has defined a curve to control the time, this correction cannot be performed
00490          *        reliably...
00491          */
00492         if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
00493                 return cframe;
00494                 
00495         /* perform the correction now... */
00496         return nlastrip_get_frame(strip, cframe, mode);
00497 }
00498 
00499 /* *************************************************** */
00500 /* NLA API */
00501 
00502 /* List of Strips ------------------------------------ */
00503 /* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
00504 
00505 /* Check if there is any space in the given list to add the given strip */
00506 short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
00507 {
00508         NlaStrip *strip;
00509         
00510         /* sanity checks */
00511         if ((strips == NULL) || IS_EQF(start, end))
00512                 return 0;
00513         if (start > end) {
00514                 puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
00515                 SWAP(float, start, end);
00516         }
00517         
00518         /* loop over NLA strips checking for any overlaps with this area... */
00519         for (strip= strips->first; strip; strip= strip->next) {
00520                 /* if start frame of strip is past the target end-frame, that means that
00521                  * we've gone past the window we need to check for, so things are fine
00522                  */
00523                 if (strip->start >= end)
00524                         return 1;
00525                 
00526                 /* if the end of the strip is greater than either of the boundaries, the range
00527                  * must fall within the extents of the strip
00528                  */
00529                 if ((strip->end > start) || (strip->end > end))
00530                         return 0;
00531         }
00532         
00533         /* if we are still here, we haven't encountered any overlapping strips */
00534         return 1;
00535 }
00536 
00537 /* Rearrange the strips in the track so that they are always in order 
00538  * (usually only needed after a strip has been moved) 
00539  */
00540 void BKE_nlastrips_sort_strips (ListBase *strips)
00541 {
00542         ListBase tmp = {NULL, NULL};
00543         NlaStrip *strip, *sstrip, *stripn;
00544         
00545         /* sanity checks */
00546         if ELEM(NULL, strips, strips->first)
00547                 return;
00548         
00549         /* we simply perform insertion sort on this list, since it is assumed that per track,
00550          * there are only likely to be at most 5-10 strips
00551          */
00552         for (strip= strips->first; strip; strip= stripn) {
00553                 short not_added = 1;
00554                 
00555                 stripn= strip->next;
00556                 
00557                 /* remove this strip from the list, and add it to the new list, searching from the end of 
00558                  * the list, assuming that the lists are in order 
00559                  */
00560                 BLI_remlink(strips, strip);
00561                 
00562                 for (sstrip= tmp.last; sstrip; sstrip= sstrip->prev) {
00563                         /* check if add after */
00564                         if (sstrip->end <= strip->start) {
00565                                 BLI_insertlinkafter(&tmp, sstrip, strip);
00566                                 not_added= 0;
00567                                 break;
00568                         }
00569                 }
00570                 
00571                 /* add before first? */
00572                 if (not_added)
00573                         BLI_addhead(&tmp, strip);
00574         }
00575         
00576         /* reassign the start and end points of the strips */
00577         strips->first= tmp.first;
00578         strips->last= tmp.last;
00579 }
00580 
00581 /* Add the given NLA-Strip to the given list of strips, assuming that it 
00582  * isn't currently a member of another list
00583  */
00584 short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
00585 {
00586         NlaStrip *ns;
00587         short not_added = 1;
00588         
00589         /* sanity checks */
00590         if ELEM(NULL, strips, strip)
00591                 return 0;
00592                 
00593         /* check if any space to add */
00594         if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0)
00595                 return 0;
00596         
00597         /* find the right place to add the strip to the nominated track */
00598         for (ns= strips->first; ns; ns= ns->next) {
00599                 /* if current strip occurs after the new strip, add it before */
00600                 if (ns->start >= strip->end) {
00601                         BLI_insertlinkbefore(strips, ns, strip);
00602                         not_added= 0;
00603                         break;
00604                 }
00605         }
00606         if (not_added) {
00607                 /* just add to the end of the list of the strips then... */
00608                 BLI_addtail(strips, strip);
00609         }
00610         
00611         /* added... */
00612         return 1;
00613 }
00614 
00615 
00616 /* Meta-Strips ------------------------------------ */
00617 
00618 /* Convert 'islands' (i.e. continuous string of) selected strips to be
00619  * contained within 'Meta-Strips' which act as strips which contain strips.
00620  *      temp: are the meta-strips to be created 'temporary' ones used for transforms?
00621  */
00622 void BKE_nlastrips_make_metas (ListBase *strips, short temp)
00623 {
00624         NlaStrip *mstrip = NULL;
00625         NlaStrip *strip, *stripn;
00626         
00627         /* sanity checks */
00628         if ELEM(NULL, strips, strips->first)
00629                 return;
00630         
00631         /* group all continuous chains of selected strips into meta-strips */
00632         for (strip= strips->first; strip; strip= stripn) {
00633                 stripn= strip->next;
00634                 
00635                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
00636                         /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
00637                         if (mstrip == NULL) {
00638                                 /* add a new meta-strip, and add it before the current strip that it will replace... */
00639                                 mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
00640                                 mstrip->type = NLASTRIP_TYPE_META;
00641                                 BLI_insertlinkbefore(strips, strip, mstrip);
00642                                 
00643                                 /* set flags */
00644                                 mstrip->flag = NLASTRIP_FLAG_SELECT;
00645                                 
00646                                 /* set temp flag if appropriate (i.e. for transform-type editing) */
00647                                 if (temp)
00648                                         mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
00649                                         
00650                                 /* set default repeat/scale values to prevent warnings */
00651                                 mstrip->repeat= mstrip->scale= 1.0f;
00652                                 
00653                                 /* make its start frame be set to the start frame of the current strip */
00654                                 mstrip->start= strip->start;
00655                         }
00656                         
00657                         /* remove the selected strips from the track, and add to the meta */
00658                         BLI_remlink(strips, strip);
00659                         BLI_addtail(&mstrip->strips, strip);
00660                         
00661                         /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
00662                         mstrip->end= strip->end;
00663                 }
00664                 else {
00665                         /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
00666                          * so stop adding strips to the current meta
00667                          */
00668                         mstrip= NULL;
00669                 }
00670         }
00671 }
00672 
00673 /* Split a meta-strip into a set of normal strips */
00674 void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip)
00675 {
00676         NlaStrip *cs, *csn;
00677         
00678         /* sanity check */
00679         if ELEM(NULL, strips, strip)
00680                 return;
00681         
00682         /* move each one of the meta-strip's children before the meta-strip
00683          * in the list of strips after unlinking them from the meta-strip
00684          */
00685         for (cs= strip->strips.first; cs; cs= csn) {
00686                 csn= cs->next;
00687                 BLI_remlink(&strip->strips, cs);
00688                 BLI_insertlinkbefore(strips, strip, cs);
00689         }
00690         
00691         /* free the meta-strip now */
00692         free_nlastrip(strips, strip);
00693 }
00694 
00695 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
00696  *      sel: only consider selected meta-strips, otherwise all meta-strips are removed
00697  *      onlyTemp: only remove the 'temporary' meta-strips used for transforms
00698  */
00699 void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp)
00700 {
00701         NlaStrip *strip, *stripn;
00702         
00703         /* sanity checks */
00704         if ELEM(NULL, strips, strips->first)
00705                 return;
00706         
00707         /* remove meta-strips fitting the criteria of the arguments */
00708         for (strip= strips->first; strip; strip= stripn) {
00709                 stripn= strip->next;
00710                 
00711                 /* check if strip is a meta-strip */
00712                 if (strip->type == NLASTRIP_TYPE_META) {
00713                         /* if check if selection and 'temporary-only' considerations are met */
00714                         if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
00715                                 if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
00716                                         BKE_nlastrips_clear_metastrip(strips, strip);
00717                                 }
00718                         }
00719                 }
00720         }
00721 }
00722 
00723 /* Add the given NLA-Strip to the given Meta-Strip, assuming that the
00724  * strip isn't attached to anyy list of strips 
00725  */
00726 short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip)
00727 {
00728         /* sanity checks */
00729         if ELEM(NULL, mstrip, strip)
00730                 return 0;
00731                 
00732         /* firstly, check if the meta-strip has space for this */
00733         if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
00734                 return 0;
00735                 
00736         /* check if this would need to be added to the ends of the meta,
00737          * and subsequently, if the neighbouring strips allow us enough room
00738          */
00739         if (strip->start < mstrip->start) {
00740                 /* check if strip to the left (if it exists) ends before the 
00741                  * start of the strip we're trying to add 
00742                  */
00743                 if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
00744                         /* add strip to start of meta's list, and expand dimensions */
00745                         BLI_addhead(&mstrip->strips, strip);
00746                         mstrip->start= strip->start;
00747                         
00748                         return 1;
00749                 }
00750                 else /* failed... no room before */
00751                         return 0;
00752         }
00753         else if (strip->end > mstrip->end) {
00754                 /* check if strip to the right (if it exists) starts before the 
00755                  * end of the strip we're trying to add 
00756                  */
00757                 if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
00758                         /* add strip to end of meta's list, and expand dimensions */
00759                         BLI_addtail(&mstrip->strips, strip);
00760                         mstrip->end= strip->end;
00761                         
00762                         return 1;
00763                 }
00764                 else /* failed... no room after */
00765                         return 0;
00766         }
00767         else {
00768                 /* just try to add to the meta-strip (no dimension changes needed) */
00769                 return BKE_nlastrips_add_strip(&mstrip->strips, strip);
00770         }
00771 }
00772 
00773 /* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively), 
00774  * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
00775  */
00776 void BKE_nlameta_flush_transforms (NlaStrip *mstrip) 
00777 {
00778         NlaStrip *strip;
00779         float oStart, oEnd, offset;
00780         float oLen, nLen;
00781         short scaleChanged= 0;
00782         
00783         /* sanity checks 
00784          *      - strip must exist
00785          *      - strip must be a meta-strip with some contents
00786          */
00787         if ELEM(NULL, mstrip, mstrip->strips.first)
00788                 return;
00789         if (mstrip->type != NLASTRIP_TYPE_META)
00790                 return;
00791                 
00792         /* get the original start/end points, and calculate the start-frame offset
00793          *      - these are simply the start/end frames of the child strips, 
00794          *        since we assume they weren't transformed yet
00795          */
00796         oStart= ((NlaStrip *)mstrip->strips.first)->start;
00797         oEnd= ((NlaStrip *)mstrip->strips.last)->end;
00798         offset= mstrip->start - oStart;
00799         
00800         /* optimisation:
00801          * don't flush if nothing changed yet
00802          *      TODO: maybe we need a flag to say always flush?
00803          */
00804         if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end))
00805                 return;
00806         
00807         /* check if scale changed */
00808         oLen = oEnd - oStart;
00809         nLen = mstrip->end - mstrip->start;
00810         if (IS_EQF(nLen, oLen) == 0)
00811                 scaleChanged= 1;
00812         
00813         /* for each child-strip, calculate new start/end points based on this new info */
00814         for (strip= mstrip->strips.first; strip; strip= strip->next) {
00815                 if (scaleChanged) {
00816                         PointerRNA ptr;
00817                         float p1, p2, nStart, nEnd;
00818                         
00819                         /* compute positions of endpoints relative to old extents of strip */
00820                         p1= (strip->start - oStart) / oLen;
00821                         p2= (strip->end - oStart) / oLen;
00822                         
00823                         /* compute the new strip endpoints using the proportions */
00824                         nStart= (p1 * nLen) + mstrip->start;
00825                         nEnd= (p2 * nLen) + mstrip->start;
00826                         
00827                         /* firstly, apply the new positions manually, then apply using RNA 
00828                          *      - first time is to make sure no truncation errors from one endpoint not being 
00829                          *        set yet occur
00830                          *      - second time is to make sure scale is computed properly...
00831                          */
00832                         strip->start= nStart;
00833                         strip->end= nEnd;
00834                         
00835                         RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
00836                         RNA_float_set(&ptr, "frame_start", nStart);
00837                         RNA_float_set(&ptr, "frame_end", nEnd);
00838                 }
00839                 else {
00840                         /* just apply the changes in offset to both ends of the strip */
00841                         strip->start += offset;
00842                         strip->end += offset;
00843                 }
00844                 
00845                 /* finally, make sure the strip's children (if it is a meta-itself), get updated */
00846                 BKE_nlameta_flush_transforms(strip);
00847         }
00848 }
00849 
00850 /* NLA-Tracks ---------------------------------------- */
00851 
00852 /* Find the active NLA-track for the given stack */
00853 NlaTrack *BKE_nlatrack_find_active (ListBase *tracks)
00854 {
00855         NlaTrack *nlt;
00856         
00857         /* sanity check */
00858         if ELEM(NULL, tracks, tracks->first)
00859                 return NULL;
00860                 
00861         /* try to find the first active track */
00862         for (nlt= tracks->first; nlt; nlt= nlt->next) {
00863                 if (nlt->flag & NLATRACK_ACTIVE)
00864                         return nlt;
00865         }
00866         
00867         /* none found */
00868         return NULL;
00869 }
00870 
00871 /* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
00872  * that has this status in its AnimData block.
00873  */
00874 void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt)
00875 {
00876         NlaTrack *nt;
00877         
00878         /* sanity check */
00879         if ELEM(NULL, adt, adt->nla_tracks.first)
00880                 return;
00881                 
00882         /* firstly, make sure 'solo' flag for all tracks is disabled */
00883         for (nt= adt->nla_tracks.first; nt; nt= nt->next) {
00884                 if (nt != nlt)
00885                         nt->flag &= ~NLATRACK_SOLO;
00886         }
00887                 
00888         /* now, enable 'solo' for the given track if appropriate */
00889         if (nlt) {
00890                 /* toggle solo status */
00891                 nlt->flag ^= NLATRACK_SOLO;
00892                 
00893                 /* set or clear solo-status on AnimData */
00894                 if (nlt->flag & NLATRACK_SOLO)
00895                         adt->flag |= ADT_NLA_SOLO_TRACK;
00896                 else
00897                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
00898         }
00899         else
00900                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
00901 }
00902 
00903 /* Make the given NLA-track the active one for the given stack. If no track is provided, 
00904  * this function can be used to simply deactivate all the NLA tracks in the given stack too.
00905  */
00906 void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
00907 {
00908         NlaTrack *nlt;
00909         
00910         /* sanity check */
00911         if ELEM(NULL, tracks, tracks->first)
00912                 return;
00913         
00914         /* deactive all the rest */
00915         for (nlt= tracks->first; nlt; nlt= nlt->next) 
00916                 nlt->flag &= ~NLATRACK_ACTIVE;
00917                 
00918         /* set the given one as the active one */
00919         if (nlt_a)
00920                 nlt_a->flag |= NLATRACK_ACTIVE;
00921 }
00922 
00923 /* Check if there is any space in the given track to add a strip of the given length */
00924 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
00925 {
00926         /* sanity checks 
00927          *      - track must exist
00928          *      - track must be editable
00929          *      - bounds cannot be equal (0-length is nasty) 
00930          */
00931         if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end))
00932                 return 0;
00933         
00934         if (start > end) {
00935                 puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
00936                 SWAP(float, start, end);
00937         }
00938         
00939         /* check if there's any space left in the track for a strip of the given length */
00940         return BKE_nlastrips_has_space(&nlt->strips, start, end);
00941 }
00942 
00943 /* Rearrange the strips in the track so that they are always in order 
00944  * (usually only needed after a strip has been moved) 
00945  */
00946 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
00947 {
00948         /* sanity checks */
00949         if ELEM(NULL, nlt, nlt->strips.first)
00950                 return;
00951         
00952         /* sort the strips with a more generic function */
00953         BKE_nlastrips_sort_strips(&nlt->strips);
00954 }
00955 
00956 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
00957  * isn't currently attached to another one 
00958  */
00959 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
00960 {
00961         /* sanity checks */
00962         if ELEM(NULL, nlt, strip)
00963                 return 0;
00964                 
00965         /* try to add the strip to the track using a more generic function */
00966         return BKE_nlastrips_add_strip(&nlt->strips, strip);
00967 }
00968 
00969 /* Get the extents of the given NLA-Track including gaps between strips,
00970  * returning whether this succeeded or not
00971  */
00972 short BKE_nlatrack_get_bounds (NlaTrack *nlt, float bounds[2])
00973 {
00974         NlaStrip *strip;
00975         
00976         /* initialise bounds */
00977         if (bounds)
00978                 bounds[0] = bounds[1] = 0.0f;
00979         else
00980                 return 0;
00981         
00982         /* sanity checks */
00983         if ELEM(NULL, nlt, nlt->strips.first)
00984                 return 0;
00985                 
00986         /* lower bound is first strip's start frame */
00987         strip = nlt->strips.first;
00988         bounds[0] = strip->start;
00989         
00990         /* upper bound is last strip's end frame */
00991         strip = nlt->strips.last;
00992         bounds[1] = strip->end;
00993         
00994         /* done */
00995         return 1;
00996 }
00997 
00998 /* NLA Strips -------------------------------------- */
00999 
01000 /* Find the active NLA-strip within the given track */
01001 NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt)
01002 {
01003         NlaStrip *strip;
01004         
01005         /* sanity check */
01006         if ELEM(NULL, nlt, nlt->strips.first)
01007                 return NULL;
01008                 
01009         /* try to find the first active strip */
01010         for (strip= nlt->strips.first; strip; strip= strip->next) {
01011                 if (strip->flag & NLASTRIP_FLAG_ACTIVE)
01012                         return strip;
01013         }
01014         
01015         /* none found */
01016         return NULL;
01017 }
01018 
01019 /* Make the given NLA-Strip the active one within the given block */
01020 void BKE_nlastrip_set_active (AnimData *adt, NlaStrip *strip)
01021 {
01022         NlaTrack *nlt;
01023         NlaStrip *nls;
01024         
01025         /* sanity checks */
01026         if (adt == NULL)
01027                 return;
01028         
01029         /* loop over tracks, deactivating*/
01030         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01031                 for (nls= nlt->strips.first; nls; nls= nls->next)  {
01032                         if (nls != strip)
01033                                 nls->flag &= ~NLASTRIP_FLAG_ACTIVE;
01034                         else
01035                                 nls->flag |= NLASTRIP_FLAG_ACTIVE;
01036                 }
01037         }
01038 }
01039 
01040 
01041 /* Does the given NLA-strip fall within the given bounds (times)? */
01042 short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max)
01043 {
01044         const float stripLen= (strip) ? strip->end - strip->start : 0.0f;
01045         const float boundsLen= (float)fabs(max - min);
01046         
01047         /* sanity checks */
01048         if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f))
01049                 return 0;
01050         
01051         /* only ok if at least part of the strip is within the bounding window
01052          *      - first 2 cases cover when the strip length is less than the bounding area
01053          *      - second 2 cases cover when the strip length is greater than the bounding area
01054          */
01055         if ( (stripLen < boundsLen) && 
01056                  !(IN_RANGE(strip->start, min, max) ||
01057                    IN_RANGE(strip->end, min, max)) )
01058         {
01059                 return 0;
01060         }
01061         if ( (stripLen > boundsLen) && 
01062                  !(IN_RANGE(min, strip->start, strip->end) ||
01063                    IN_RANGE(max, strip->start, strip->end)) )
01064         {
01065                 return 0;
01066         }
01067         
01068         /* should be ok! */
01069         return 1;
01070 }
01071 
01072 /* Recalculate the start and end frames for the current strip, after changing
01073  * the extents of the action or the mapping (repeats or scale factor) info
01074  */
01075 void BKE_nlastrip_recalculate_bounds (NlaStrip *strip)
01076 {
01077         float actlen, mapping;
01078         
01079         /* sanity checks
01080          *      - must have a strip
01081          *      - can only be done for action clips
01082          */
01083         if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP))
01084                 return;
01085                 
01086         /* calculate new length factors */
01087         actlen= strip->actend - strip->actstart;
01088         if (IS_EQF(actlen, 0.0f)) actlen= 1.0f;
01089         
01090         mapping= strip->scale * strip->repeat;
01091         
01092         /* adjust endpoint of strip in response to this */
01093         if (IS_EQF(mapping, 0.0f) == 0)
01094                 strip->end = (actlen * mapping) + strip->start;
01095 }
01096 
01097 /* Is the given NLA-strip the first one to occur for the given AnimData block */
01098 // TODO: make this an api method if necesary, but need to add prefix first
01099 static short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
01100 {
01101         NlaTrack *nlt;
01102         NlaStrip *ns;
01103         
01104         /* sanity checks */
01105         if ELEM(NULL, adt, strip)
01106                 return 0;
01107                 
01108         /* check if strip has any strips before it */
01109         if (strip->prev)
01110                 return 0;
01111                 
01112         /* check other tracks to see if they have a strip that's earlier */
01113         // TODO: or should we check that the strip's track is also the first?
01114         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01115                 /* only check the first strip, assuming that they're all in order */
01116                 ns= nlt->strips.first;
01117                 if (ns) {
01118                         if (ns->start < strip->start)
01119                                 return 0;
01120                 }
01121         }       
01122         
01123         /* should be first now */
01124         return 1;
01125 }
01126 
01127 /* Animated Strips ------------------------------------------- */
01128 
01129 /* Check if the given NLA-Track has any strips with own F-Curves */
01130 short BKE_nlatrack_has_animated_strips (NlaTrack *nlt)
01131 {
01132         NlaStrip *strip;
01133         
01134         /* sanity checks */
01135         if ELEM(NULL, nlt, nlt->strips.first)
01136                 return 0;
01137                 
01138         /* check each strip for F-Curves only (don't care about whether the flags are set) */
01139         for (strip= nlt->strips.first; strip; strip= strip->next) {
01140                 if (strip->fcurves.first)
01141                         return 1;
01142         }
01143         
01144         /* none found */
01145         return 0;
01146 }
01147 
01148 /* Check if given NLA-Tracks have any strips with own F-Curves */
01149 short BKE_nlatracks_have_animated_strips (ListBase *tracks)
01150 {
01151         NlaTrack *nlt;
01152         
01153         /* sanity checks */
01154         if ELEM(NULL, tracks, tracks->first)
01155                 return 0;
01156                 
01157         /* check each track, stopping on the first hit */
01158         for (nlt= tracks->first; nlt; nlt= nlt->next) {
01159                 if (BKE_nlatrack_has_animated_strips(nlt))
01160                         return 1;
01161         }
01162         
01163         /* none found */
01164         return 0;
01165 }
01166 
01167 /* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
01168 void BKE_nlastrip_validate_fcurves (NlaStrip *strip) 
01169 {
01170         FCurve *fcu;
01171         
01172         /* sanity checks */
01173         if (strip == NULL)
01174                 return;
01175         
01176         /* if controlling influence... */
01177         if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
01178                 /* try to get F-Curve */
01179                 fcu= list_find_fcurve(&strip->fcurves, "influence", 0);
01180                 
01181                 /* add one if not found */
01182                 if (fcu == NULL) {
01183                         /* make new F-Curve */
01184                         fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
01185                         BLI_addtail(&strip->fcurves, fcu);
01186                         
01187                         /* set default flags */
01188                         fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
01189                         
01190                         /* store path - make copy, and store that */
01191                         fcu->rna_path= BLI_strdupn("influence", 9);
01192                         
01193                         // TODO: insert a few keyframes to ensure default behaviour?
01194                 }
01195         }
01196         
01197         /* if controlling time... */
01198         if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
01199                 /* try to get F-Curve */
01200                 fcu= list_find_fcurve(&strip->fcurves, "strip_time", 0);
01201                 
01202                 /* add one if not found */
01203                 if (fcu == NULL) {
01204                         /* make new F-Curve */
01205                         fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
01206                         BLI_addtail(&strip->fcurves, fcu);
01207                         
01208                         /* set default flags */
01209                         fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
01210                         
01211                         /* store path - make copy, and store that */
01212                         fcu->rna_path= BLI_strdupn("strip_time", 10);
01213                         
01214                         // TODO: insert a few keyframes to ensure default behaviour?
01215                 }
01216         }
01217 }
01218 
01219 /* Sanity Validation ------------------------------------ */
01220 
01221 static int nla_editbone_name_check(void *arg, const char *name)
01222 {
01223         return BLI_ghash_haskey((GHash *)arg, (void *)name);
01224 }
01225 
01226 /* Find (and set) a unique name for a strip from the whole AnimData block 
01227  * Uses a similar method to the BLI method, but is implemented differently
01228  * as we need to ensure that the name is unique over several lists of tracks,
01229  * not just a single track.
01230  */
01231 void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip)
01232 {
01233         GHash *gh;
01234         NlaStrip *tstrip;
01235         NlaTrack *nlt;
01236         
01237         /* sanity checks */
01238         if ELEM(NULL, adt, strip)
01239                 return;
01240                 
01241         /* give strip a default name if none already */
01242         if (strip->name[0]==0) {
01243                 switch (strip->type) {
01244                         case NLASTRIP_TYPE_CLIP: /* act-clip */
01245                                 sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>"));
01246                                 break;
01247                         case NLASTRIP_TYPE_TRANSITION: /* transition */
01248                                 sprintf(strip->name, "Transition");
01249                                 break;
01250                         case NLASTRIP_TYPE_META: /* meta */
01251                                 sprintf(strip->name, "Meta");
01252                                 break;
01253                         default:
01254                                 sprintf(strip->name, "NLA Strip");
01255                                 break;
01256                 }
01257         }
01258         
01259         /* build a hash-table of all the strips in the tracks 
01260          *      - this is easier than iterating over all the tracks+strips hierarchy everytime
01261          *        (and probably faster)
01262          */
01263         gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "nlastrip_validate_name gh");
01264         
01265         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01266                 for (tstrip= nlt->strips.first; tstrip; tstrip= tstrip->next) {
01267                         /* don't add the strip of interest */
01268                         if (tstrip == strip) 
01269                                 continue;
01270                         
01271                         /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
01272                         BLI_ghash_insert(gh, tstrip->name, tstrip);
01273                 }
01274         }
01275         
01276         /* if the hash-table has a match for this name, try other names... 
01277          *      - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
01278          */
01279         BLI_uniquename_cb(nla_editbone_name_check, (void *)gh, "NlaStrip", '.', strip->name, sizeof(strip->name));
01280 
01281         /* free the hash... */
01282         BLI_ghash_free(gh, NULL, NULL);
01283 }
01284 
01285 /* ---- */
01286 
01287 /* Get strips which overlap the given one at the start/end of its range 
01288  *      - strip: strip that we're finding overlaps for
01289  *      - track: nla-track that the overlapping strips should be found from
01290  *      - start, end: frames for the offending endpoints
01291  */
01292 static void nlastrip_get_endpoint_overlaps (NlaStrip *strip, NlaTrack *track, float **start, float **end)
01293 {
01294         NlaStrip *nls;
01295         
01296         /* find strips that overlap over the start/end of the given strip,
01297          * but which don't cover the entire length 
01298          */
01299         // TODO: this scheme could get quite slow for doing this on many strips...
01300         for (nls= track->strips.first; nls; nls= nls->next) {
01301                 /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */
01302                 if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
01303                         *start= NULL;
01304                         *end= NULL;
01305                         return;
01306                 }
01307                 
01308                 /* check if strip doesn't even occur anywhere near... */
01309                 if (nls->end < strip->start)
01310                         continue; /* skip checking this strip... not worthy of mention */
01311                 if (nls->start > strip->end)
01312                         return; /* the range we're after has already passed */
01313                         
01314                 /* if this strip is not part of an island of continuous strips, it can be used
01315                  *      - this check needs to be done for each end of the strip we try and use...
01316                  */
01317                 if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end)==0) {
01318                         if ((nls->end > strip->start) && (nls->end < strip->end))
01319                                 *start= &nls->end;
01320                 }
01321                 if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start)==0) {
01322                         if ((nls->start < strip->end) && (nls->start > strip->start))
01323                                 *end= &nls->start;
01324                 }
01325         }
01326 }
01327 
01328 /* Determine auto-blending for the given strip */
01329 static void BKE_nlastrip_validate_autoblends (NlaTrack *nlt, NlaStrip *nls)
01330 {
01331         float *ps=NULL, *pe=NULL;
01332         float *ns=NULL, *ne=NULL;
01333         
01334         /* sanity checks */
01335         if ELEM(NULL, nls, nlt)
01336                 return;
01337         if ((nlt->prev == NULL) && (nlt->next == NULL))
01338                 return;
01339         if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS)==0)
01340                 return;
01341         
01342         /* get test ranges */
01343         if (nlt->prev)
01344                 nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
01345         if (nlt->next)
01346                 nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
01347                 
01348         /* set overlaps for this strip 
01349          *      - don't use the values obtained though if the end in question 
01350          *        is directly followed/preceeded by another strip, forming an 
01351          *        'island' of continuous strips
01352          */
01353         if ( (ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start)==0) )
01354         {
01355                 /* start overlaps - pick the largest overlap */
01356                 if ( ((ps && ns) && (*ps > *ns)) || (ps) )
01357                         nls->blendin= *ps - nls->start;
01358                 else
01359                         nls->blendin= *ns - nls->start;
01360         }
01361         else /* no overlap allowed/needed */
01362                 nls->blendin= 0.0f;
01363                 
01364         if ( (pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end)==0) )
01365         {
01366                 /* end overlaps - pick the largest overlap */
01367                 if ( ((pe && ne) && (*pe > *ne)) || (pe) )
01368                         nls->blendout= nls->end - *pe;
01369                 else
01370                         nls->blendout= nls->end - *ne;
01371         }
01372         else /* no overlap allowed/needed */
01373                 nls->blendout= 0.0f;
01374 }
01375 
01376 /* Ensure that auto-blending and other settings are set correctly */
01377 void BKE_nla_validate_state (AnimData *adt)
01378 {
01379         NlaStrip *strip, *fstrip=NULL;
01380         NlaTrack *nlt;
01381         
01382         /* sanity checks */
01383         if ELEM(NULL, adt, adt->nla_tracks.first)
01384                 return;
01385                 
01386         /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */
01387         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01388                 for (strip= nlt->strips.first; strip; strip= strip->next) {
01389                         /* auto-blending first */
01390                         BKE_nlastrip_validate_autoblends(nlt, strip);
01391                         
01392                         /* extend mode - find first strip */
01393                         if ((fstrip == NULL) || (strip->start < fstrip->start))
01394                                 fstrip= strip;
01395                 }
01396         }
01397         
01398         /* second pass over the strips to adjust the extend-mode to fix any problems */
01399         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01400                 for (strip= nlt->strips.first; strip; strip= strip->next) {
01401                         /* apart from 'nothing' option which user has to explicitly choose, we don't really know if 
01402                          * we should be overwriting the extend setting (but assume that's what the user wanted)
01403                          */
01404                         // TODO: 1 solution is to tie this in with auto-blending...
01405                         if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
01406                                 if (strip == fstrip)
01407                                         strip->extendmode= NLASTRIP_EXTEND_HOLD;
01408                                 else
01409                                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
01410                         }
01411                 }
01412         }
01413 }
01414 
01415 /* Core Tools ------------------------------------------- */
01416 
01417 /* For the given AnimData block, add the active action to the NLA
01418  * stack (i.e. 'push-down' action). The UI should only allow this 
01419  * for normal editing only (i.e. not in editmode for some strip's action),
01420  * so no checks for this are performed.
01421  */
01422 // TODO: maybe we should have checks for this too...
01423 void BKE_nla_action_pushdown (AnimData *adt)
01424 {
01425         NlaStrip *strip;
01426         
01427         /* sanity checks */
01428         // TODO: need to report the error for this
01429         if ELEM(NULL, adt, adt->action) 
01430                 return;
01431                 
01432         /* if the action is empty, we also shouldn't try to add to stack, 
01433          * as that will cause us grief down the track
01434          */
01435         // TODO: what about modifiers?
01436         if (action_has_motion(adt->action) == 0) {
01437                 printf("BKE_nla_action_pushdown(): action has no data \n");
01438                 return;
01439         }
01440         
01441         /* add a new NLA strip to the track, which references the active action */
01442         strip= add_nlastrip_to_stack(adt, adt->action);
01443         
01444         /* do other necessary work on strip */  
01445         if (strip) {
01446                 /* clear reference to action now that we've pushed it onto the stack */
01447                 id_us_min(&adt->action->id);
01448                 adt->action= NULL;
01449                 
01450                 /* if the strip is the first one in the track it lives in, check if there
01451                  * are strips in any other tracks that may be before this, and set the extend
01452                  * mode accordingly
01453                  */
01454                 if (nlastrip_is_first(adt, strip) == 0) {
01455                         /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
01456                          * so that it doesn't override strips in previous tracks
01457                          */
01458                         // FIXME: this needs to be more automated, since user can rearrange strips
01459                         strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD;
01460                 }
01461                 
01462                 /* make strip the active one... */
01463                 BKE_nlastrip_set_active(adt, strip);
01464         }
01465 }
01466 
01467 
01468 /* Find the active strip + track combo, and set them up as the tweaking track,
01469  * and return if successful or not.
01470  */
01471 short BKE_nla_tweakmode_enter (AnimData *adt)
01472 {
01473         NlaTrack *nlt, *activeTrack=NULL;
01474         NlaStrip *strip, *activeStrip=NULL;
01475         
01476         /* verify that data is valid */
01477         if ELEM(NULL, adt, adt->nla_tracks.first)
01478                 return 0;
01479                 
01480         /* if block is already in tweakmode, just leave, but we should report 
01481          * that this block is in tweakmode (as our returncode)
01482          */
01483         if (adt->flag & ADT_NLA_EDIT_ON)
01484                 return 1;
01485                 
01486         /* go over the tracks, finding the active one, and its active strip
01487          *      - if we cannot find both, then there's nothing to do
01488          */
01489         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01490                 /* check if active */
01491                 if (nlt->flag & NLATRACK_ACTIVE) {
01492                         /* store reference to this active track */
01493                         activeTrack= nlt;
01494                         
01495                         /* now try to find active strip */
01496                         activeStrip= BKE_nlastrip_find_active(nlt);
01497                         break;
01498                 }       
01499         }
01500         if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) {
01501                 if (G.f & G_DEBUG) {
01502                         printf("NLA tweakmode enter - neither active requirement found \n");
01503                         printf("\tactiveTrack = %p, activeStrip = %p \n", (void *)activeTrack, (void *)activeStrip);
01504                 }
01505                 return 0;
01506         }
01507                 
01508         /* go over all the tracks up to the active one, tagging each strip that uses the same 
01509          * action as the active strip, but leaving everything else alone
01510          */
01511         for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) {
01512                 for (strip= nlt->strips.first; strip; strip= strip->next) {
01513                         if (strip->act == activeStrip->act)
01514                                 strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
01515                         else
01516                                 strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
01517                 }
01518         }
01519         
01520         
01521         /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled 
01522          *      - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
01523          */
01524         for (nlt= activeTrack; nlt; nlt= nlt->next)
01525                 nlt->flag |= NLATRACK_DISABLED;
01526         
01527         /* handle AnimData level changes:
01528          *      - 'real' active action to temp storage (no need to change user-counts)
01529          *      - action of active strip set to be the 'active action', and have its usercount incremented
01530          *      - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
01531          *      - take note of the active strip for mapping-correction of keyframes in the action being edited
01532          */
01533         adt->tmpact= adt->action;
01534         adt->action= activeStrip->act;
01535         adt->actstrip= activeStrip;
01536         id_us_plus(&activeStrip->act->id);
01537         adt->flag |= ADT_NLA_EDIT_ON;
01538         
01539         /* done! */
01540         return 1;
01541 }
01542 
01543 /* Exit tweakmode for this AnimData block */
01544 void BKE_nla_tweakmode_exit (AnimData *adt)
01545 {
01546         NlaStrip *strip;
01547         NlaTrack *nlt;
01548         
01549         /* verify that data is valid */
01550         if ELEM(NULL, adt, adt->nla_tracks.first)
01551                 return;
01552                 
01553         /* hopefully the flag is correct - skip if not on */
01554         if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
01555                 return;
01556                 
01557         // TODO: need to sync the user-strip with the new state of the action!
01558                 
01559         /* for all Tracks, clear the 'disabled' flag
01560          * for all Strips, clear the 'tweak-user' flag
01561          */
01562         for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
01563                 nlt->flag &= ~NLATRACK_DISABLED;
01564                 
01565                 for (strip= nlt->strips.first; strip; strip= strip->next) 
01566                         strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
01567         }
01568         
01569         /* handle AnimData level changes:
01570          *      - 'temporary' active action needs its usercount decreased, since we're removing this reference
01571          *      - 'real' active action is restored from storage
01572          *      - storage pointer gets cleared (to avoid having bad notes hanging around)
01573          *      - editing-flag for this AnimData block should also get turned off
01574          *      - clear pointer to active strip
01575          */
01576         if (adt->action) adt->action->id.us--;
01577         adt->action= adt->tmpact;
01578         adt->tmpact= NULL;
01579         adt->actstrip= NULL;
01580         adt->flag &= ~ADT_NLA_EDIT_ON;
01581 }
01582 
01583 /* Baking Tools ------------------------------------------- */
01584 
01585 static void BKE_nla_bake (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag))
01586 {
01587 
01588         /* verify that data is valid 
01589          *      1) Scene and AnimData must be provided 
01590          *      2) there must be tracks to merge...
01591          */
01592         if ELEM3(NULL, scene, adt, adt->nla_tracks.first)
01593                 return;
01594         
01595         /* if animdata currently has an action, 'push down' this onto the stack first */
01596         if (adt->action)
01597                 BKE_nla_action_pushdown(adt);
01598         
01599         /* get range of motion to bake, and the channels involved... */
01600         
01601         /* temporarily mute the action, and start keying to it */
01602         
01603         /* start keying... */
01604         
01605         /* unmute the action */
01606 }
01607 
01608 /* *************************************************** */