Blender V2.61 - r43446

nla.c

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