diff options
55 files changed, 3893 insertions, 1096 deletions
diff --git a/release/ui/buttons_data_modifier.py b/release/ui/buttons_data_modifier.py index c087e5f5e36..6de2d645471 100644 --- a/release/ui/buttons_data_modifier.py +++ b/release/ui/buttons_data_modifier.py @@ -23,9 +23,9 @@ class DATA_PT_modifiers(DataButtonsPanel): row.itemL(); for md in ob.modifiers: - box = layout.template_modifier(md) + box = layout.template_modifier(context, md) - if box: + if md.expanded: if md.type == 'ARMATURE': self.armature(box, md) if md.type == 'ARRAY': @@ -103,7 +103,7 @@ class DATA_PT_modifiers(DataButtonsPanel): if md.fit_type == 'FIT_LENGTH': layout.itemR(md, "length") if md.fit_type == 'FIT_CURVE': - layout.itemR(md, "curve") + layout.itemR(md, "curve") split = layout.split() @@ -188,7 +188,7 @@ class DATA_PT_modifiers(DataButtonsPanel): layout.itemL(text="See Collision panel.") def curve(self, layout, md): - layout.itemR(md, "object") + layout.itemR(md, "curve") layout.itemR(md, "vertex_group") layout.itemR(md, "deform_axis") @@ -238,7 +238,7 @@ class DATA_PT_modifiers(DataButtonsPanel): # Missing: "Reset" and "Recenter" def lattice(self, layout, md): - layout.itemR(md, "object") + layout.itemR(md, "lattice") layout.itemR(md, "vertex_group") def mask(self, layout, md): @@ -250,7 +250,7 @@ class DATA_PT_modifiers(DataButtonsPanel): layout.itemR(md, "inverse") def meshdeform(self, layout, md): - layout.itemR(md, "object") + layout.itemR(md, "mesh") layout.itemR(md, "vertex_group") layout.itemR(md, "invert") layout.itemR(md, "precision") @@ -402,4 +402,4 @@ class DATA_PT_modifiers(DataButtonsPanel): col.itemR(md, "width", slider=True) col.itemR(md, "narrowness", slider=True) -bpy.types.register(DATA_PT_modifiers)
\ No newline at end of file +bpy.types.register(DATA_PT_modifiers) diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 67eb2ed58bf..cc10a4071a6 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -68,6 +68,9 @@ void make_local_action(struct bAction *act); /* Some kind of bounding box operation on the action */ void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden); +/* Does action have any motion data at all? */ +short action_has_motion(const struct bAction *act); + /* Action Groups API ----------------- */ /* Make the given Action Group the active one */ diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 9b8a2990fe5..7058b9d236a 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -108,11 +108,15 @@ struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type); void fcurve_copy_modifiers(ListBase *dst, ListBase *src); void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm); void fcurve_free_modifiers(struct FCurve *fcu); -void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end); struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu); void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm); +float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime); +void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime); + +void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end); + /* ************** F-Curves API ******************** */ /* -------- Data Managemnt -------- */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index ce182267b93..e598394cc60 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -45,7 +45,6 @@ void *copy_libblock(void *rt); void id_lib_extern(struct ID *id); void id_us_plus(struct ID *id); -void id_us_min(struct ID *id); int check_for_dupid(struct ListBase *lb, struct ID *id, char *name); int new_id(struct ListBase *lb, struct ID *id, const char *name); diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 230096d7ea7..3c3abe11da3 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -17,12 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung * All rights reserved. * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Joshua Leung (full recode) * * ***** END GPL LICENSE BLOCK ***** */ @@ -30,15 +30,38 @@ #ifndef BKE_NLA_H #define BKE_NLA_H -struct bActionStrip; -struct ListBase; -struct Object; +struct AnimData; +struct NlaStrip; +struct NlaTrack; +struct bAction; + +/* ----------------------------- */ +/* Data Management */ + +void free_nlastrip(ListBase *strips, struct NlaStrip *strip); +void free_nlatrack(ListBase *tracks, struct NlaTrack *nlt); +void free_nladata(ListBase *tracks); + +struct NlaStrip *copy_nlastrip(struct NlaStrip *strip); +struct NlaTrack *copy_nlatrack(struct NlaTrack *nlt); +void copy_nladata(ListBase *dst, ListBase *src); + +struct NlaTrack *add_nlatrack(struct AnimData *adt); +struct NlaStrip *add_nlastrip(struct bAction *act); +struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act); + +/* ----------------------------- */ +/* API */ + +struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks); +void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt); + +short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end); +void BKE_nlatrack_sort_strips(struct NlaTrack *nlt); + +short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max); + +void BKE_nla_action_pushdown(struct AnimData *adt); -void free_actionstrip (struct bActionStrip* strip); -void free_nlastrips (struct ListBase *nlalist); -void copy_nlastrips (struct ListBase *dst, struct ListBase *src); -void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src); -void find_stridechannel(struct Object *ob, struct bActionStrip *strip); -struct bActionStrip *convert_action_to_strip (struct Object *ob); #endif diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d54bc749b71..bb458cc7e25 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -717,50 +717,45 @@ static bActionStrip *get_active_strip(Object *ob) return NULL; } -/* non clipped mapping of strip */ -static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert) -{ - float length, actlength, repeat, scale; - - if (strip->repeat == 0.0f) strip->repeat = 1.0f; - repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat); - - if (strip->scale == 0.0f) strip->scale= 1.0f; - scale = (float)fabs(strip->scale); /* scale must be positive (for now) */ - - actlength = strip->actend-strip->actstart; - if (actlength == 0.0f) actlength = 1.0f; - length = repeat * scale * actlength; - - /* invert = convert action-strip time to global time */ - if (invert) - return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; - else - return repeat*actlength*(cframe - strip->start)/length + strip->actstart; -} - /* if the conditions match, it converts current time to strip time */ +// TODO: change this adt float get_action_frame(Object *ob, float cframe) { bActionStrip *strip= get_active_strip(ob); - if(strip) - return get_actionstrip_frame(strip, cframe, 0); + //if(strip) + // return get_actionstrip_frame(strip, cframe, 0); return cframe; } /* inverted, strip time to current time */ +// TODO: change this to adt float get_action_frame_inv(Object *ob, float cframe) { bActionStrip *strip= get_active_strip(ob); - if(strip) - return get_actionstrip_frame(strip, cframe, 1); + //if(strip) + // return get_actionstrip_frame(strip, cframe, 1); return cframe; } - +/* Check if the given action has any keyframes */ +short action_has_motion(const bAction *act) +{ + FCurve *fcu; + + /* return on the first F-Curve that has some keyframes/samples defined */ + if (act) { + for (fcu= act->curves.first; fcu; fcu= fcu->next) { + if (fcu->totvert) + return 1; + } + } + + /* nothing found */ + return 0; +} /* Calculate the extents of given action */ void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden) diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 30dcb383ef6..652f733d553 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -5,6 +5,8 @@ #include <stdio.h> #include <string.h> #include <stddef.h> +#include <float.h> +#include <math.h> #include "MEM_guardedalloc.h" @@ -15,6 +17,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_fcurve.h" +#include "BKE_nla.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_utildefines.h" @@ -116,6 +119,9 @@ void BKE_free_animdata (ID *id) if (adt->action) adt->action->id.us--; + /* free nla data */ + free_nladata(&adt->nla_tracks); + /* free drivers - stored as a list of F-Curves */ free_fcurves(&adt->drivers); @@ -147,7 +153,7 @@ AnimData *BKE_copy_animdata (AnimData *adt) dadt->action= copy_action(adt->action); /* duplicate NLA data */ - // XXX todo... + copy_nladata(&dadt->nla_tracks, &adt->nla_tracks); /* duplicate drivers (F-Curves) */ copy_fcurves(&dadt->drivers, &adt->drivers); @@ -544,19 +550,17 @@ typedef struct NlaEvalStrip { struct NlaEvalStrip *next, *prev; NlaTrack *track; /* track that this strip belongs to */ - NlaStrip *strip; /* strip that's being used */ - NlaStrip *sblend; /* strip that's being blended towards (if applicable) */ + NlaStrip *strip; /* strip that's being used */ short track_index; /* the index of the track within the list */ short strip_mode; /* which end of the strip are we looking at */ } NlaEvalStrip; -/* bNlaEvalStrip->strip_mode */ +/* NlaEvalStrip->strip_mode */ enum { NES_TIME_BEFORE = -1, NES_TIME_WITHIN, NES_TIME_AFTER, - NES_TIME_AFTER_BLEND } eNlaEvalStrip_StripMode; @@ -565,8 +569,9 @@ enum { typedef struct NlaEvalChannel { struct NlaEvalChannel *next, *prev; - char *path; /* ready-to-use path (i.e. remapped already) */ - int array_index; /* if applicable... */ + PointerRNA ptr; /* pointer to struct containing property to use */ + PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */ + int index; /* array index (where applicable) */ float value; /* value of this channel */ } NlaEvalChannel; @@ -574,24 +579,98 @@ typedef struct NlaEvalChannel { /* ---------------------- */ -/* evaluate the F-Curves controlling settings for the NLA-strips (currently, not relinkable) */ -static void nlastrip_evaluate_fcurves (NlaStrip *strip, float ctime) +/* non clipped mapping for strip-time <-> global time + * invert = convert action-strip time to global time + */ +static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert) { - //PointerRNA actstrip_ptr; - //FCurve *fcu; + float length, actlength, repeat, scale; + + /* get number of repeats */ + if (strip->repeat == 0.0f) strip->repeat = 1.0f; + repeat = strip->repeat; + + /* scaling */ + if (strip->scale == 0.0f) strip->scale= 1.0f; + scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */ + + /* length of referenced action */ + actlength = strip->actend-strip->actstart; + if (actlength == 0.0f) actlength = 1.0f; - /* create RNA-pointer needed to set values */ - //RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &actstrip_ptr); + /* length of strip */ + length = repeat * scale * actlength; - /* execute these settings as per normal */ - //animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime); + /* reversed = play strip backwards */ + if (strip->flag & NLASTRIP_FLAG_REVERSE) { + // FIXME: verify these + /* invert = convert action-strip time to global time */ + if (invert) + return length*(strip->actend - cframe)/(repeat*actlength) + strip->start; + else + return strip->actend - repeat*actlength*(cframe - strip->start)/length; + } + else { + /* invert = convert action-strip time to global time */ + if (invert) + return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; + else + return repeat*actlength*(cframe - strip->start)/length + strip->actstart; + } } +/* calculate influence of strip based for given frame based on blendin/out values */ +static float nlastrip_get_influence (NlaStrip *strip, float cframe) +{ + /* sanity checks - normalise the blendin/out values? */ + strip->blendin= (float)fabs(strip->blendin); + strip->blendout= (float)fabs(strip->blendout); + + /* result depends on where frame is in respect to blendin/out values */ + // the +0.0001 factors are to combat rounding errors + if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) { + /* there is some blend-in */ + return (float)(fabs(cframe - strip->start) + 0.0001) / (strip->blendin); + } + else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) { + /* there is some blend-out */ + return (float)(fabs(strip->end - cframe) + 0.0001) / (strip->blendout); + } + else { + /* in the middle of the strip, we should be full strength */ + return 1.0f; + } +} -/* gets the strip active at the current time for a track */ +/* evaluate the evaluation time and influence for the strip, storing the results in the strip */ +void nlastrip_evaluate_controls (NlaStrip *strip, float ctime) +{ + /* firstly, analytically generate values for influence and time (if applicable) */ + if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) + strip->strip_time= nlastrip_get_frame(strip, ctime, 1); /* last arg '1' means current time to 'strip'/action time */ + if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) + strip->influence= nlastrip_get_influence(strip, ctime); + + /* now strip's evaluate F-Curves for these settings (if applicable) */ + if (strip->fcurves.first) { +#if 0 + PointerRNA strip_ptr; + FCurve *fcu; + + /* create RNA-pointer needed to set values */ + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); + + /* execute these settings as per normal */ + animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime); +#endif + } +} + + +/* gets the strip active at the current time for a track for evaluation purposes */ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime) { - NlaStrip *strip, *astrip=NULL, *bstrip=NULL; + NlaStrip *strip, *estrip=NULL; NlaEvalStrip *nes; short side= 0; @@ -601,90 +680,317 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index /* loop over strips, checking if they fall within the range */ for (strip= nlt->strips.first; strip; strip= strip->next) { - /* only consider if: - * - current time occurs within strip's extents - * - current time occurs before strip (if it is the first) - * - current time occurs after strip (if hold is on) - * - current time occurs between strips (1st of those isn't holding) - blend! - */ + /* check if current time occurs within this strip */ if (IN_RANGE(ctime, strip->start, strip->end)) { - astrip= strip; + /* this strip is active, so try to use it */ + estrip= strip; side= NES_TIME_WITHIN; break; } - else if (ctime < strip->start) { + + /* if time occurred before current strip... */ + if (ctime < strip->start) { if (strip == nlt->strips.first) { - astrip= strip; + /* before first strip - only try to use it if it extends backwards in time too */ + if (strip->extendmode == NLASTRIP_EXTEND_HOLD) + estrip= strip; + + /* side is 'before' regardless of whether there's a useful strip */ side= NES_TIME_BEFORE; - break; } else { - astrip= strip->prev; + /* before next strip - previous strip has ended, but next hasn't begun, + * so blending mode depends on whether strip is being held or not... + * - only occurs when no transition strip added, otherwise the transition would have + * been picked up above... + */ + strip= strip->prev; - if (astrip->flag & NLASTRIP_HOLDLASTFRAME) { - side= NES_TIME_AFTER; - break; - } - else { - bstrip= strip; - side= NES_TIME_AFTER_BLEND; - break; - } + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip= strip; + side= NES_TIME_AFTER; } + break; + } + + /* if time occurred after current strip... */ + if (ctime > strip->end) { + /* only if this is the last strip should we do anything, and only if that is being held */ + if (strip == nlt->strips.last) { + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip= strip; + + side= NES_TIME_AFTER; + break; + } + + /* otherwise, skip... as the 'before' case will catch it more elegantly! */ } } - /* check if strip has been found (and whether it has data worth considering) */ - if (ELEM(NULL, astrip, astrip->act)) - return; - if (astrip->flag & NLASTRIP_MUTE) + /* check if a valid strip was found + * - must not be muted (i.e. will have contribution + */ + if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) return; - /* check if blending between strips */ - if (side == NES_TIME_AFTER_BLEND) { - /* blending between strips... so calculate influence+act_time of both */ - nlastrip_evaluate_fcurves(astrip, ctime); - nlastrip_evaluate_fcurves(bstrip, ctime); - - if ((astrip->influence <= 0.0f) && (bstrip->influence <= 0.0f)) - return; - } - else { - /* calculate/set the influence+act_time of this strip - don't consider if 0 influence */ - nlastrip_evaluate_fcurves(astrip, ctime); + /* evaluate strip's evaluation controls + * - skip if no influence (i.e. same effect as muting the strip) + * - negative influence is not supported yet... how would that be defined? + */ + // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... + // TODO: should we clamp the time to only be on the endpoints of the strip? + nlastrip_evaluate_controls(estrip, ctime); + if (estrip->influence <= 0.0f) // XXX is it useful to invert the strip? + return; - if (astrip->influence <= 0.0f) - return; + /* check if strip has valid data to evaluate */ + switch (estrip->type) { + case NLASTRIP_TYPE_CLIP: + /* clip must have some action to evaluate */ + if (estrip->act == NULL) + return; + break; + case NLASTRIP_TYPE_TRANSITION: + /* there must be strips to transition from and to (i.e. prev and next required) */ + // TODO: what happens about cross-track transitions? + if (ELEM(NULL, estrip->prev, estrip->next)) + return; + break; } - - /* allocate new eval-strip for this strip + add to stack */ + /* add to list of strips we need to evaluate */ nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); nes->track= nlt; - nes->strip= astrip; - nes->sblend= bstrip; - nes->track_index= index; + nes->strip= estrip; nes->strip_mode= side; + nes->track_index= index; BLI_addtail(list, nes); } /* ---------------------- */ +/* find an NlaEvalChannel that matches the given criteria + * - ptr and prop are the RNA data to find a match for + */ +static NlaEvalChannel *nlaevalchan_find_match (ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index) +{ + NlaEvalChannel *nec; + + /* sanity check */ + if (channels == NULL) + return NULL; + + /* loop through existing channels, checking for a channel which affects the same property */ + for (nec= channels->first; nec; nec= nec->next) { + /* - comparing the PointerRNA's is done by comparing the pointers + * to the actual struct the property resides in, since that all the + * other data stored in PointerRNA cannot allow us to definitively + * identify the data + */ + if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index)) + return nec; + } + + /* not found */ + return NULL; +} + +/* verify that an appropriate NlaEvalChannel for this F-Curve exists */ +static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan) +{ + NlaEvalChannel *nec; + NlaStrip *strip= nes->strip; + PropertyRNA *prop; + PointerRNA new_ptr; + char *path = NULL; + short free_path=0; + + /* sanity checks */ + if (channels == NULL) + return NULL; + + /* get RNA pointer+property info from F-Curve for more convenient handling */ + /* get path, remapped as appropriate to work in its new environment */ + free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path); + + /* a valid property must be available, and it must be animateable */ + if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0) { + if (G.f & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path \n"); + return NULL; + } + /* only ok if animateable */ + else if (RNA_property_animateable(&new_ptr, prop) == 0) { + if (G.f & G_DEBUG) printf("NLA Strip Eval: Property not animateable \n"); + return NULL; + } + + /* try to find a match */ + nec= nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index); + + /* allocate a new struct for this if none found */ + if (nec == NULL) { + nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel"); + *newChan= 1; + BLI_addtail(channels, nec); + + nec->ptr= new_ptr; + nec->prop= prop; + nec->index= fcu->array_index; + } + + /* we can now return */ + return nec; +} + +/* accumulate (i.e. blend) the given value on to the channel it affects */ +static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value) +{ + NlaStrip *strip= nes->strip; + float inf= strip->influence; + + /* if channel is new, just store value regardless of blending factors, etc. */ + if (newChan) { + nec->value= value; + return; + } + + /* premultiply the value by the weighting factor */ + if (IS_EQ(inf, 0)) return; + value *= inf; + + /* perform blending */ + switch (strip->blendmode) { + case NLASTRIP_MODE_ADD: + /* simply add the scaled value on to the stack */ + nec->value += value; + break; + + case NLASTRIP_MODE_SUBTRACT: + /* simply subtract the scaled value from the stack */ + nec->value -= value; + break; + + case NLASTRIP_MODE_MULTIPLY: + /* multiply the scaled value with the stack */ + nec->value *= value; + break; + + case NLASTRIP_MODE_BLEND: + default: // TODO: do we really want to blend by default? it seems more uses might prefer add... + /* do linear interpolation + * - the influence of the accumulated data (elsewhere, that is called dstweight) + * is 1 - influence, since the strip's influence is srcweight + */ + nec->value= nec->value * (1.0f - inf) + value; + break; + } +} + +/* ---------------------- */ + +/* evaluate action-clip strip */ +static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes) +{ + NlaStrip *strip= nes->strip; + FCurve *fcu; + float evaltime; + + /* evaluate strip's modifiers which modify time to evaluate the base curves at */ + evaltime= evaluate_time_fmodifiers(&strip->modifiers, NULL, 0.0f, strip->strip_time); + + /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */ + for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) { + NlaEvalChannel *nec; + float value = 0.0f; + short newChan = -1; + + /* check if this curve should be skipped */ + if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) + continue; + + /* evaluate the F-Curve's value for the time given in the strip + * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this + */ + value= evaluate_fcurve(fcu, evaltime); + + /* apply strip's F-Curve Modifiers on this value + * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval) + */ + evaluate_value_fmodifiers(&strip->modifiers, fcu, &value, strip->strip_time); + + + /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) + * stored in this channel if it has been used already + */ + nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan); + if (nec) + nlaevalchan_accumulate(nec, nes, newChan, value); + } +} + /* evaluates the given evaluation strip */ -// FIXME: will we need the evaluation cache table set up to blend stuff in? // TODO: only evaluate here, but flush in one go using the accumulated channels at end... -static void nlastrip_ctime_evaluate (ListBase *channels, NlaEvalStrip *nes, float ctime) +static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes) { - // 1. (in old code) was to extract 'IPO-channels' from actions - // 2. blend between the 'accumulated' data, and the new data + /* actions to take depend on the type of strip */ + switch (nes->strip->type) { + case NLASTRIP_TYPE_CLIP: /* action-clip */ + nlastrip_evaluate_actionclip(ptr, channels, nes); + break; + case NLASTRIP_TYPE_TRANSITION: /* transition */ + // XXX code this... + break; + } } /* write the accumulated settings to */ -static void nladata_flush_channels (PointerRNA *ptr, ListBase *channels) +static void nladata_flush_channels (ListBase *channels) { + NlaEvalChannel *nec; + /* sanity checks */ + if (channels == NULL) + return; + + /* for each channel with accumulated values, write its value on the property it affects */ + for (nec= channels->first; nec; nec= nec->next) { + PointerRNA *ptr= &nec->ptr; + PropertyRNA *prop= nec->prop; + int array_index= nec->index; + float value= nec->value; + + /* write values - see animsys_write_rna_setting() to sync the code */ + switch (RNA_property_type(prop)) + { + case PROP_BOOLEAN: + if (RNA_property_array_length(prop)) + RNA_property_boolean_set_index(ptr, prop, array_index, (int)value); + else + RNA_property_boolean_set(ptr, prop, (int)value); + break; + case PROP_INT: + if (RNA_property_array_length(prop)) + RNA_property_int_set_index(ptr, prop, array_index, (int)value); + else + RNA_property_int_set(ptr, prop, (int)value); + break; + case PROP_FLOAT: + if (RNA_property_array_length(prop)) + RNA_property_float_set_index(ptr, prop, array_index, value); + else + RNA_property_float_set(ptr, prop, value); + break; + case PROP_ENUM: + RNA_property_enum_set(ptr, prop, (int)value); + break; + default: + // can't do anything with other types of property.... + break; + } + } } /* ---------------------- */ @@ -713,10 +1019,10 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime) /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ for (nes= estrips.first; nes; nes= nes->next) - nlastrip_ctime_evaluate(&echannels, nes, ctime); + nlastrip_evaluate(ptr, &echannels, nes); /* 3. flush effects of accumulating channels in NLA to the actual data they affect */ - nladata_flush_channels(ptr, &echannels); + nladata_flush_channels(&echannels); /* 4. free temporary evaluation data */ BLI_freelistN(&estrips); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index ad8115ba9aa..6a3870f8f31 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -2190,34 +2190,6 @@ void fcurve_free_modifiers (FCurve *fcu) } } -/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined - * by start and end (inclusive). - */ -void fcurve_bake_modifiers (FCurve *fcu, int start, int end) -{ - ChannelDriver *driver; - - /* sanity checks */ - // TODO: make these tests report errors using reports not printf's - if ELEM(NULL, fcu, fcu->modifiers.first) { - printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); - return; - } - - /* temporarily, disable driver while we sample, so that they don't influence the outcome */ - driver= fcu->driver; - fcu->driver= NULL; - - /* bake the modifiers, by sampling the curve at each frame */ - fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); - - /* free the modifiers now */ - fcurve_free_modifiers(fcu); - - /* restore driver */ - fcu->driver= driver; -} - /* Find the active F-Curve Modifier */ FModifier *fcurve_find_active_modifier (FCurve *fcu) { @@ -2255,6 +2227,98 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm) fcm->flag |= FMODIFIER_FLAG_ACTIVE; } +/* Evaluation API --------------------------- */ + +/* evaluate time modifications imposed by some F-Curve Modifiers + * - this step acts as an optimisation to prevent the F-Curve stack being evaluated + * several times by modifiers requesting the time be modified, as the final result + * would have required using the modified time + * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be + * working on the 'global' result of the modified curve, not some localised segment, + * so nevaltime gets set to whatever the last time-modifying modifier likes... + * - we start from the end of the stack, as only the last one matters for now + */ +float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime) +{ + FModifier *fcm; + float m_evaltime= evaltime; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return evaltime; + + /* find the first modifier from end of stack that modifies time, and calculate the time the modifier + * would calculate time at + */ + for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* only evaluate if there's a callback for this */ + // TODO: implement the 'influence' control feature... + if (fmi && fmi->evaluate_modifier_time) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) + m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + break; + } + } + + /* return the modified evaltime */ + return m_evaltime; +} + +/* Evalautes the given set of F-Curve Modifiers using the given data + * Should only be called after evaluate_time_fmodifiers() has been called... + */ +void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime) +{ + FModifier *fcm; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return; + + /* evaluate modifiers */ + for (fcm= modifiers->first; fcm; fcm= fcm->next) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* only evaluate if there's a callback for this */ + // TODO: implement the 'influence' control feature... + if (fmi && fmi->evaluate_modifier) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) + fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime); + } + } +} + + +/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined + * by start and end (inclusive). + */ +void fcurve_bake_modifiers (FCurve *fcu, int start, int end) +{ + ChannelDriver *driver; + + /* sanity checks */ + // TODO: make these tests report errors using reports not printf's + if ELEM(NULL, fcu, fcu->modifiers.first) { + printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); + return; + } + + /* temporarily, disable driver while we sample, so that they don't influence the outcome */ + driver= fcu->driver; + fcu->driver= NULL; + + /* bake the modifiers, by sampling the curve at each frame */ + fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); + + /* free the modifiers now */ + fcurve_free_modifiers(fcu); + + /* restore driver */ + fcu->driver= driver; +} + /* ***************************** F-Curve - Evaluation ********************************* */ /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") @@ -2262,7 +2326,6 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm) */ float evaluate_fcurve (FCurve *fcu, float evaltime) { - FModifier *fcm; float cvalue= 0.0f; float devaltime; @@ -2275,28 +2338,8 @@ float evaluate_fcurve (FCurve *fcu, float evaltime) evaltime= cvalue= evaluate_driver(fcu->driver, evaltime); } - /* evaluate time modifications imposed by some F-Curve Modifiers - * - this step acts as an optimisation to prevent the F-Curve stack being evaluated - * several times by modifiers requesting the time be modified, as the final result - * would have required using the modified time - * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be - * working on the 'global' result of the modified curve, not some localised segment, - * so nevaltime gets set to whatever the last time-modifying modifier likes... - * - we start from the end of the stack, as only the last one matters for now - */ - devaltime= evaltime; - - for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) { - FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - - /* only evaluate if there's a callback for this */ - // TODO: implement the 'influence' control feature... - if (fmi && fmi->evaluate_modifier_time) { - if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) - devaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); - break; - } - } + /* evaluate modifiers which modify time to evaluate the base curve at */ + devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime); /* evaluate curve-data * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying @@ -2308,16 +2351,7 @@ float evaluate_fcurve (FCurve *fcu, float evaltime) cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime); /* evaluate modifiers */ - for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) { - FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - - /* only evaluate if there's a callback for this */ - // TODO: implement the 'influence' control feature... - if (fmi && fmi->evaluate_modifier) { - if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) - fmi->evaluate_modifier(fcu, fcm, &cvalue, evaltime); - } - } + evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime); /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) * here so that the curve can be sampled correctly diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 90ab4e05d44..d0e4c1a15bc 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -142,12 +142,6 @@ void id_us_plus(ID *id) } } -void id_us_min(ID *id) -{ - if(id) - id->us--; -} - ListBase *wich_libbase(Main *mainlib, short type) { switch( type ) { diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index dc2bf26759f..cf115cb6faf 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -17,171 +17,551 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung * All rights reserved. * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Joshua Leung (full recode) * * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <math.h> +#include <float.h> #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "DNA_space_types.h" -#include "DNA_nla_types.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" -#include "DNA_ID.h" -#include "DNA_ipo_types.h" -#include "DNA_object_types.h" -#include "BKE_nla.h" +#include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_fcurve.h" +#include "BKE_nla.h" #include "BKE_blender.h" #include "BKE_library.h" -#include "BKE_object.h" /* for convert_action_to_strip(ob) */ +#include "BKE_object.h" +#include "BKE_utildefines.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif -/* NOTE: in group.c the strips get copied for group-nla override, this assumes - that strips are one single block, without additional data to be copied */ -void copy_actionstrip (bActionStrip **dst, bActionStrip **src){ - bActionStrip *dstrip; - bActionStrip *sstrip = *src; +/* *************************************************** */ +/* Data Management */ - if (!*src){ - *dst=NULL; +/* Freeing ------------------------------------------- */ + +/* Remove the given NLA strip from the NLA track it occupies, free the strip's data, + * and the strip itself. + */ +// TODO: with things like transitions, should these get freed too? Maybe better as a UI tool +void free_nlastrip (ListBase *strips, NlaStrip *strip) +{ + FModifier *fcm, *fmn; + + /* sanity checks */ + if (strip == NULL) return; + + /* remove reference to action */ + if (strip->act) + strip->act->id.us--; + + /* free remapping info */ + //if (strip->remap) + // BKE_animremap_free(); + + /* free own F-Curves */ + free_fcurves(&strip->fcurves); + + /* free F-Modifiers */ + for (fcm= strip->modifiers.first; fcm; fcm= fmn) { + fmn= fcm->next; + + BLI_remlink(&strip->modifiers, fcm); + fcurve_remove_modifier(NULL, fcm); } + + /* free the strip itself */ + if (strips) + BLI_freelinkN(strips, strip); + else + MEM_freeN(strip); +} - *dst = MEM_dupallocN(sstrip); - - dstrip = *dst; - if (dstrip->act) - dstrip->act->id.us++; - - if (dstrip->ipo) - dstrip->ipo->id.us++; +/* Remove the given NLA track from the set of NLA tracks, free the track's data, + * and the track itself. + */ +void free_nlatrack (ListBase *tracks, NlaTrack *nlt) +{ + NlaStrip *strip, *stripn; - if (dstrip->modifiers.first) { - BLI_duplicatelist (&dstrip->modifiers, &sstrip->modifiers); + /* sanity checks */ + if (nlt == NULL) + return; + + /* free strips */ + for (strip= nlt->strips.first; strip; strip= stripn) { + stripn= strip->next; + free_nlastrip(&nlt->strips, strip); } + /* free NLA track itself now */ + if (tracks) + BLI_freelinkN(tracks, nlt); + else + MEM_freeN(nlt); } -void copy_nlastrips (ListBase *dst, ListBase *src) +/* Free the elements of type NLA Tracks provided in the given list, but do not free + * the list itself since that is not free-standing + */ +void free_nladata (ListBase *tracks) { - bActionStrip *strip; - - dst->first=dst->last=NULL; + NlaTrack *nlt, *nltn; + + /* sanity checks */ + if ELEM(NULL, tracks, tracks->first) + return; + + /* free tracks one by one */ + for (nlt= tracks->first; nlt; nlt= nltn) { + nltn= nlt->next; + free_nlatrack(tracks, nlt); + } + + /* clear the list's pointers to be safe */ + tracks->first= tracks->last= NULL; +} - BLI_duplicatelist (dst, src); +/* Copying ------------------------------------------- */ - /* Update specific data */ - if (!dst->first) - return; +/* Copy NLA strip */ +NlaStrip *copy_nlastrip (NlaStrip *strip) +{ + NlaStrip *strip_d; + + /* sanity check */ + if (strip == NULL) + return NULL; + + /* make a copy */ + strip_d= MEM_dupallocN(strip); + strip_d->next= strip_d->prev= NULL; + + /* increase user-count of action */ + if (strip_d->act) + strip_d->act->id.us++; + + /* copy F-Curves and modifiers */ + copy_fcurves(&strip_d->fcurves, &strip->fcurves); + fcurve_copy_modifiers(&strip_d->modifiers, &strip->modifiers); + + /* return the strip */ + return strip_d; +} - for (strip = dst->first; strip; strip=strip->next){ - if (strip->act) - strip->act->id.us++; - if (strip->ipo) - strip->ipo->id.us++; - if (strip->modifiers.first) { - ListBase listb; - BLI_duplicatelist (&listb, &strip->modifiers); - strip->modifiers= listb; - } +/* Copy NLA Track */ +NlaTrack *copy_nlatrack (NlaTrack *nlt) +{ + NlaStrip *strip, *strip_d; + NlaTrack *nlt_d; + + /* sanity check */ + if (nlt == NULL) + return NULL; + + /* make a copy */ + nlt_d= MEM_dupallocN(nlt); + nlt_d->next= nlt_d->prev= NULL; + + /* make a copy of all the strips, one at a time */ + nlt_d->strips.first= nlt_d->strips.last= NULL; + + for (strip= nlt->strips.first; strip; strip= strip->next) { + strip_d= copy_nlastrip(strip); + BLI_addtail(&nlt_d->strips, strip_d); } + + /* return the copy */ + return nlt_d; } -/* from editnla, for convert_action_to_strip -- no UI code so should be ok here.. */ -void find_stridechannel(Object *ob, bActionStrip *strip) +/* Copy all NLA data */ +void copy_nladata (ListBase *dst, ListBase *src) { - if(ob && ob->pose) { - bPoseChannel *pchan; - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) - if(pchan->flag & POSE_STRIDE) - break; - if(pchan) - BLI_strncpy(strip->stridechannel, pchan->name, 32); - else - strip->stridechannel[0]= 0; + NlaTrack *nlt, *nlt_d; + + /* sanity checks */ + if ELEM(NULL, dst, src) + return; + + /* copy each NLA-track, one at a time */ + for (nlt= src->first; nlt; nlt= nlt->next) { + /* make a copy, and add the copy to the destination list */ + nlt_d= copy_nlatrack(nlt); + BLI_addtail(dst, nlt_d); } } -//called by convert_nla / bpy api with an object with the action to be converted to a new strip -bActionStrip *convert_action_to_strip (Object *ob) +/* Adding ------------------------------------------- */ + +/* Add a NLA Track to the given AnimData */ +NlaTrack *add_nlatrack (AnimData *adt) { - bActionStrip *nstrip; + NlaTrack *nlt; + + /* sanity checks */ + if (adt == NULL) + return NULL; + + /* allocate new track */ + nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack"); + + /* set settings requiring the track to not be part of the stack yet */ + nlt->flag = NLATRACK_SELECTED; + nlt->index= BLI_countlist(&adt->nla_tracks); + + /* add track to stack, and make it the active one */ + BLI_addtail(&adt->nla_tracks, nlt); + BKE_nlatrack_set_active(&adt->nla_tracks, nlt); + + /* must have unique name, but we need to seed this */ + sprintf(nlt->name, "NlaTrack"); + BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64); + + /* return the new track */ + return nlt; +} - /* Make new actionstrip */ - nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip"); - - /* Link the action to the nstrip */ - nstrip->act = ob->action; - id_us_plus(&nstrip->act->id); - calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend, 1); - nstrip->start = nstrip->actstart; - nstrip->end = nstrip->actend; - nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; - - find_stridechannel(ob, nstrip); - //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */ - - nstrip->repeat = 1.0; +/* Add a NLA Strip referencing the given Action */ +NlaStrip *add_nlastrip (bAction *act) +{ + NlaStrip *strip; + + /* sanity checks */ + if (act == NULL) + return NULL; + + /* allocate new strip */ + strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip"); + + /* generic settings + * - selected flag to highlight this to the user + * - auto-blends to ensure that blend in/out values are automatically + * determined by overlaps of strips + * - (XXX) synchronisation of strip-length in accordance with changes to action-length + * is not done though, since this should only really happens in editmode for strips now + * though this decision is still subject to further review... + */ + strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS; + + /* assign the action reference */ + strip->act= act; + id_us_plus(&act->id); + + /* determine initial range + * - strip length cannot be 0... ever... + */ + calc_action_range(strip->act, &strip->actstart, &strip->actend, 1); + + strip->start = strip->actstart; + strip->end = (IS_EQ(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f): (strip->actend); + + /* strip should be referenced as-is */ + strip->scale= 1.0f; + strip->repeat = 1.0f; + + /* return the new strip */ + return strip; +} - if(ob->nlastrips.first == NULL) - ob->nlaflag |= OB_NLA_OVERRIDE; +/* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */ +NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act) +{ + NlaStrip *strip, *ns; + NlaTrack *nlt; + short not_added = 1; + + /* sanity checks */ + if ELEM(NULL, adt, act) + return NULL; - BLI_addtail(&ob->nlastrips, nstrip); - return nstrip; /* is created, malloced etc. here so is safe to just return the pointer? - this is needed for setting this active in UI, and probably useful for API too */ + /* create a new NLA strip */ + strip= add_nlastrip(act); + if (strip == NULL) + return NULL; + /* check if the last NLA-track (if it exists) has any space for this strip: + * - if so, add this strip to that track + */ + if ( (adt->nla_tracks.last == NULL) || + (BKE_nlatrack_has_space(adt->nla_tracks.last, strip->start, strip->end)==0) ) + { + /* no space, so add to a new track... */ + nlt= add_nlatrack(adt); + } + else + { + /* there's some space, so add to this track... */ + nlt= adt->nla_tracks.last; + } + + /* find the right place to add the strip to the nominated track */ + for (ns= nlt->strips.first; ns; ns= ns->next) { + /* if current strip occurs after the new strip, add it before */ + if (ns->start > strip->end) { + BLI_insertlinkbefore(&nlt->strips, ns, strip); + not_added= 0; + break; + } + } + if (not_added) { + /* just add to the end of the list of the strips then... */ + BLI_addtail(&nlt->strips, strip); + } + + + /* returns the strip added */ + return strip; } +/* *************************************************** */ +/* Basic Utilities */ + +/* NLA-Tracks ---------------------------------------- */ -/* not strip itself! */ -void free_actionstrip(bActionStrip* strip) +/* Find the active NLA-track for the given stack */ +NlaTrack *BKE_nlatrack_find_active (ListBase *tracks) +{ + NlaTrack *nlt; + + /* sanity check */ + if ELEM(NULL, tracks, tracks->first) + return NULL; + + /* try to find the first active track */ + for (nlt= tracks->first; nlt; nlt= nlt->next) { + if (nlt->flag & NLATRACK_ACTIVE) + return nlt; + } + + /* none found */ + return NULL; +} + +/* Make the given NLA-track the active one for the given stack. If no track is provided, + * this function can be used to simply deactivate all the NLA tracks in the given stack too. + */ +void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a) { - if (!strip) + NlaTrack *nlt; + + /* sanity check */ + if ELEM(NULL, tracks, tracks->first) return; + + /* deactive all the rest */ + for (nlt= tracks->first; nlt; nlt= nlt->next) + nlt->flag &= ~NLATRACK_ACTIVE; + + /* set the given one as the active one */ + if (nlt_a) + nlt_a->flag |= NLATRACK_ACTIVE; +} - if (strip->act){ - strip->act->id.us--; - strip->act = NULL; - } - if (strip->ipo){ - strip->ipo->id.us--; - strip->ipo = NULL; +/* Check if there is any space in the last track to add the given strip */ +short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end) +{ + NlaStrip *strip; + + /* sanity checks */ + if ((nlt == NULL) || IS_EQ(start, end)) + return 0; + if (start > end) { + puts("BKE_nlatrack_has_space error... start and end arguments swapped"); + SWAP(float, start, end); } - if (strip->modifiers.first) { - BLI_freelistN(&strip->modifiers); + + /* loop over NLA strips checking for any overlaps with this area... */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* if start frame of strip is past the target end-frame, that means that + * we've gone past the window we need to check for, so things are fine + */ + if (strip->start > end) + return 1; + + /* if the end of the strip is greater than either of the boundaries, the range + * must fall within the extents of the strip + */ + if ((strip->end > start) || (strip->end > end)) + return 0; } + /* if we are still here, we haven't encountered any overlapping strips */ + return 1; } -void free_nlastrips (ListBase *nlalist) +/* Rearrange the strips in the track so that they are always in order + * (usually only needed after a strip has been moved) + */ +void BKE_nlatrack_sort_strips (NlaTrack *nlt) { - bActionStrip *strip; - - if (!nlalist->first) + ListBase tmp = {NULL, NULL}; + NlaStrip *strip, *sstrip; + + /* sanity checks */ + if ELEM(NULL, nlt, nlt->strips.first) return; + + /* we simply perform insertion sort on this list, since it is assumed that per track, + * there are only likely to be at most 5-10 strips + */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + short not_added = 1; + + /* remove this strip from the list, and add it to the new list, searching from the end of + * the list, assuming that the lists are in order + */ + BLI_remlink(&nlt->strips, strip); + + for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) { + /* check if add after */ + if (sstrip->end < strip->start) { + BLI_insertlinkafter(&tmp, sstrip, strip); + not_added= 0; + break; + } + } + + /* add before first? */ + if (not_added) + BLI_addhead(&tmp, strip); + } + + /* reassign the start and end points of the strips */ + nlt->strips.first= tmp.first; + nlt->strips.last= tmp.last; +} - /* Do any specific freeing */ - for (strip=nlalist->first; strip; strip=strip->next) +/* NLA Strips -------------------------------------- */ + +/* Does the given NLA-strip fall within the given bounds (times)? */ +short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max) +{ + const float stripLen= (strip) ? strip->end - strip->start : 0.0f; + const float boundsLen= (float)fabs(max - min); + + /* sanity checks */ + if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f)) + return 0; + + /* only ok if at least part of the strip is within the bounding window + * - first 2 cases cover when the strip length is less than the bounding area + * - second 2 cases cover when the strip length is greater than the bounding area + */ + if ( (stripLen < boundsLen) && + !(IN_RANGE(strip->start, min, max) || + IN_RANGE(strip->end, min, max)) ) + { + return 0; + } + if ( (stripLen > boundsLen) && + !(IN_RANGE(min, strip->start, strip->end) || + IN_RANGE(max, strip->start, strip->end)) ) { - free_actionstrip (strip); - }; + return 0; + } + + /* should be ok! */ + return 1; +} - /* Free the whole list */ - BLI_freelistN(nlalist); +/* Is the given NLA-strip the first one to occur for the given AnimData block */ +// TODO: make this an api method if necesary, but need to add prefix first +short nlastrip_is_first (AnimData *adt, NlaStrip *strip) +{ + NlaTrack *nlt; + NlaStrip *ns; + + /* sanity checks */ + if ELEM(NULL, adt, strip) + return 0; + + /* check if strip has any strips before it */ + if (strip->prev) + return 0; + + /* check other tracks to see if they have a strip that's earlier */ + // TODO: or should we check that the strip's track is also the first? + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + /* only check the first strip, assuming that they're all in order */ + ns= nlt->strips.first; + if (ns) { + if (ns->start < strip->start) + return 0; + } + } + + /* should be first now */ + return 1; } + +/* Tools ------------------------------------------- */ + +/* For the given AnimData block, add the active action to the NLA + * stack (i.e. 'push-down' action). The UI should only allow this + * for normal editing only (i.e. not in editmode for some strip's action), + * so no checks for this are performed. + */ +// TODO: maybe we should have checks for this too... +void BKE_nla_action_pushdown (AnimData *adt) +{ + NlaStrip *strip; + + /* sanity checks */ + // TODO: need to report the error for this + if ELEM(NULL, adt, adt->action) + return; + + /* if the action is empty, we also shouldn't try to add to stack, + * as that will cause us grief down the track + */ + // TODO: what about modifiers? + if (action_has_motion(adt->action) == 0) { + printf("BKE_nla_action_pushdown(): action has no data \n"); + return; + } + + /* add a new NLA strip to the track, which references the active action */ + strip= add_nlastrip_to_stack(adt, adt->action); + + /* do other necessary work on strip */ + if (strip) { + /* clear reference to action now that we've pushed it onto the stack */ + adt->action->id.us--; + adt->action= NULL; + + /* if the strip is the first one in the track it lives in, check if there + * are strips in any other tracks that may be before this, and set the extend + * mode accordingly + */ + if (nlastrip_is_first(adt, strip) == 0) { + /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD, + * so that it doesn't override strips in previous tracks + */ + strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD; + } + } +} + +/* *************************************************** */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d7619010808..7a83162f7a7 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1193,18 +1193,12 @@ Object *copy_object(Object *ob) armature_rebuild_pose(obn, obn->data); } copy_defgroups(&obn->defbase, &ob->defbase); -#if 0 // XXX old animation system - copy_nlastrips(&obn->nlastrips, &ob->nlastrips); -#endif // XXX old animation system copy_constraints(&obn->constraints, &ob->constraints); /* increase user numbers */ id_us_plus((ID *)obn->data); -#if 0 // XXX old animation system - id_us_plus((ID *)obn->ipo); - id_us_plus((ID *)obn->action); -#endif // XXX old animation system id_us_plus((ID *)obn->dup_group); + // FIXME: add this for animdata too... for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f8657125014..160b0943928 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1657,10 +1657,26 @@ static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbas /* Data Linking ----------------------------- */ +static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list) +{ + FModifier *fcm; + + for (fcm= list->first; fcm; fcm= fcm->next) { + /* data for specific modifiers */ + switch (fcm->type) { + case FMODIFIER_TYPE_PYTHON: + { + FMod_Python *data= (FMod_Python *)fcm->data; + data->script = newlibadr(fd, id->lib, data->script); + } + break; + } + } +} + static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) { FCurve *fcu; - FModifier *fcm; /* relink ID-block references... */ for (fcu= list->first; fcu; fcu= fcu->next) { @@ -1674,16 +1690,45 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) } /* modifiers */ - for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) { - /* data for specific modifiers */ - switch (fcm->type) { - case FMODIFIER_TYPE_PYTHON: - { - FMod_Python *data= (FMod_Python *)fcm->data; - data->script = newlibadr(fd, id->lib, data->script); - } - break; + lib_link_fmodifiers(fd, id, &fcu->modifiers); + } +} + + +/* NOTE: this assumes that link_list has already been called on the list */ +static void direct_link_fmodifiers(FileData *fd, ListBase *list) +{ + FModifier *fcm; + + for (fcm= list->first; fcm; fcm= fcm->next) { + /* relink general data */ + fcm->data = newdataadr(fd, fcm->data); + fcm->edata= NULL; + + /* do relinking of data for specific types */ + switch (fcm->type) { + case FMODIFIER_TYPE_GENERATOR: + { + FMod_Generator *data= (FMod_Generator *)fcm->data; + + data->coefficients= newdataadr(fd, data->coefficients); + } + break; + case FMODIFIER_TYPE_ENVELOPE: + { + FMod_Envelope *data= (FMod_Envelope *)fcm->data; + + data->data= newdataadr(fd, data->data); } + break; + case FMODIFIER_TYPE_PYTHON: + { + FMod_Python *data= (FMod_Python *)fcm->data; + + data->prop = newdataadr(fd, data->prop); + IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + break; } } } @@ -1692,7 +1737,6 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list) static void direct_link_fcurves(FileData *fd, ListBase *list) { FCurve *fcu; - FModifier *fcm; /* link F-Curve data to F-Curve again (non ID-libs) */ for (fcu= list->first; fcu; fcu= fcu->next) { @@ -1720,37 +1764,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list) /* modifiers */ link_list(fd, &fcu->modifiers); - for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) { - /* relink general data */ - fcm->data = newdataadr(fd, fcm->data); - fcm->edata= NULL; - - /* do relinking of data for specific types */ - switch (fcm->type) { - case FMODIFIER_TYPE_GENERATOR: - { - FMod_Generator *data= (FMod_Generator *)fcm->data; - - data->coefficients= newdataadr(fd, data->coefficients); - } - break; - case FMODIFIER_TYPE_ENVELOPE: - { - FMod_Envelope *data= (FMod_Envelope *)fcm->data; - - data->data= newdataadr(fd, data->data); - } - break; - case FMODIFIER_TYPE_PYTHON: - { - FMod_Python *data= (FMod_Python *)fcm->data; - - data->prop = newdataadr(fd, data->prop); - IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - } - break; - } - } + direct_link_fmodifiers(fd, &fcu->modifiers); } } @@ -1802,6 +1816,44 @@ static void direct_link_action(FileData *fd, bAction *act) } } + +static void lib_link_nladata (FileData *fd, ID *id, ListBase *list) +{ + NlaTrack *nlt; + NlaStrip *strip; + + /* we only acare about the NLA strips inside the tracks */ + for (nlt= list->first; nlt; nlt= nlt->next) { + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* reassign the counted-reference to action */ + strip->act = newlibadr_us(fd, id->lib, strip->act); + } + } +} + +/* NOTE: this assumes that link_list has already been called on the list */ +static void direct_link_nladata(FileData *fd, ListBase *list) +{ + NlaTrack *nlt; + NlaStrip *strip; + + for (nlt= list->first; nlt; nlt= nlt->next) { + /* relink list of strips */ + link_list(fd, &nlt->strips); + + /* relink strip data */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* strip's F-Curves */ + link_list(fd, &strip->fcurves); + direct_link_fcurves(fd, &strip->fcurves); + + /* strip's F-Modifiers */ + link_list(fd, &strip->modifiers); + direct_link_fcurves(fd, &strip->modifiers); + } + } +} + /* ------- */ static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list) @@ -1851,7 +1903,7 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt) /* overrides don't have lib-link for now, so no need to do anything */ /* link NLA-data */ - // TODO... + lib_link_nladata(fd, id, &adt->nla_tracks); } static void direct_link_animdata(FileData *fd, AnimData *adt) @@ -1868,7 +1920,8 @@ static void direct_link_animdata(FileData *fd, AnimData *adt) // TODO... /* link NLA-data */ - // TODO... + link_list(fd, &adt->nla_tracks); + direct_link_nladata(fd, &adt->nla_tracks); } /* ************ READ NODE TREE *************** */ @@ -4635,6 +4688,11 @@ static void direct_link_screen(FileData *fd, bScreen *sc) sipo->ads= newdataadr(fd, sipo->ads); sipo->ghostCurves.first= sipo->ghostCurves.last= NULL; } + else if (sl->spacetype==SPACE_NLA) { + SpaceNla *snla= (SpaceNla*)sl; + + snla->ads= newdataadr(fd, snla->ads); + } else if (sl->spacetype==SPACE_OUTLINER) { SpaceOops *soops= (SpaceOops*) sl; @@ -5623,7 +5681,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom= V2D_LOCKZOOM_Y; - ar->v2d.align= V2D_ALIGN_NO_POS_Y; + ar->v2d.align= V2D_ALIGN_NO_NEG_Y; ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; break; } @@ -9319,6 +9377,8 @@ static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list) static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt) { FCurve *fcd; + NlaTrack *nlt; + NlaStrip *strip; /* own action */ expand_doit(fd, mainvar, adt->action); @@ -9331,6 +9391,12 @@ static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt) for (dtar= driver->targets.first; dtar; dtar= dtar->next) expand_doit(fd, mainvar, dtar->id); } + + /* nla-data - referenced actions */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + for (strip= nlt->strips.first; strip; strip= strip->next) + expand_doit(fd, mainvar, strip->act); + } } static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 943e23861ad..5cf46b6fd28 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -760,10 +760,59 @@ static void write_actuators(WriteData *wd, ListBase *lb) } } +static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) +{ + FModifier *fcm; + + /* Modifiers */ + for (fcm= fmodifiers->first; fcm; fcm= fcm->next) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* Write the specific data */ + if (fmi && fcm->data) { + /* firstly, just write the plain fmi->data struct */ + writestruct(wd, DATA, fmi->structName, 1, fcm->data); + + /* do any modifier specific stuff */ + switch (fcm->type) { + case FMODIFIER_TYPE_GENERATOR: + { + FMod_Generator *data= (FMod_Generator *)fcm->data; + + /* write coefficients array */ + if (data->coefficients) + writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients); + } + break; + case FMODIFIER_TYPE_ENVELOPE: + { + FMod_Envelope *data= (FMod_Envelope *)fcm->data; + + /* write envelope data */ + if (data->data) + writedata(wd, DATA, sizeof(FCM_EnvelopeData)*(data->totvert), data->data); + } + break; + case FMODIFIER_TYPE_PYTHON: + { + FMod_Python *data = (FMod_Python *)fcm->data; + + /* Write ID Properties -- and copy this comment EXACTLY for easy finding + of library blocks that implement this.*/ + IDP_WriteProperty(data->prop, wd); + } + break; + } + } + + /* Write the modifier */ + writestruct(wd, DATA, "FModifier", 1, fcm); + } +} + static void write_fcurves(WriteData *wd, ListBase *fcurves) { FCurve *fcu; - FModifier *fcm; for (fcu=fcurves->first; fcu; fcu=fcu->next) { /* F-Curve */ @@ -794,50 +843,8 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) } } - /* Modifiers */ - for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) { - FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - - /* Write the specific data */ - if (fmi && fcm->data) { - /* firstly, just write the plain fmi->data struct */ - writestruct(wd, DATA, fmi->structName, 1, fcm->data); - - /* do any modifier specific stuff */ - switch (fcm->type) { - case FMODIFIER_TYPE_GENERATOR: - { - FMod_Generator *data= (FMod_Generator *)fcm->data; - - /* write coefficients array */ - if (data->coefficients) - writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients); - } - break; - case FMODIFIER_TYPE_ENVELOPE: - { - FMod_Envelope *data= (FMod_Envelope *)fcm->data; - - /* write envelope data */ - if (data->data) - writedata(wd, DATA, sizeof(FCM_EnvelopeData)*(data->totvert), data->data); - } - break; - case FMODIFIER_TYPE_PYTHON: - { - FMod_Python *data = (FMod_Python *)fcm->data; - - /* Write ID Properties -- and copy this comment EXACTLY for easy finding - of library blocks that implement this.*/ - IDP_WriteProperty(data->prop, wd); - } - break; - } - } - - /* Write the modifier */ - writestruct(wd, DATA, "FModifier", 1, fcm); - } + /* write F-Modifiers */ + write_fmodifiers(wd, &fcu->modifiers); } } @@ -888,6 +895,29 @@ static void write_keyingsets(WriteData *wd, ListBase *list) } } +static void write_nladata(WriteData *wd, ListBase *nlabase) +{ + NlaTrack *nlt; + NlaStrip *strip; + + /* write all the tracks */ + for (nlt= nlabase->first; nlt; nlt= nlt->next) { + /* write the track first */ + writestruct(wd, DATA, "NlaTrack", 1, nlt); + + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* write the strip first */ + writestruct(wd, DATA, "NlaStrip", 1, strip); + + /* write the strip's F-Curves and modifiers */ + write_fcurves(wd, &strip->fcurves); + write_fmodifiers(wd, &strip->modifiers); + + // TODO write the remaps + } + } +} + static void write_animdata(WriteData *wd, AnimData *adt) { AnimOverride *aor; @@ -899,14 +929,17 @@ static void write_animdata(WriteData *wd, AnimData *adt) write_fcurves(wd, &adt->drivers); /* write overrides */ + // FIXME: are these needed? for (aor= adt->overrides.first; aor; aor= aor->next) { /* overrides consist of base data + rna_path */ writestruct(wd, DATA, "AnimOverride", 1, aor); writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path); } + // TODO write the remaps (if they are needed) + /* write NLA data */ - // XXX todo... + write_nladata(wd, &adt->nla_tracks); } static void write_constraints(WriteData *wd, ListBase *conlist) @@ -1876,7 +1909,10 @@ static void write_screens(WriteData *wd, ListBase *scrbase) writestruct(wd, DATA, "SpaceSound", 1, sl); } else if(sl->spacetype==SPACE_NLA){ - writestruct(wd, DATA, "SpaceNla", 1, sl); + SpaceNla *snla= (SpaceNla *)sl; + + writestruct(wd, DATA, "SpaceNla", 1, snla); + if(snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads); } else if(sl->spacetype==SPACE_TIME){ writestruct(wd, DATA, "SpaceTime", 1, sl); diff --git a/source/blender/editors/animation/anim_channels.c b/source/blender/editors/animation/anim_channels.c index 9e0e50a8de5..658bff73978 100644 --- a/source/blender/editors/animation/anim_channels.c +++ b/source/blender/editors/animation/anim_channels.c @@ -87,32 +87,6 @@ /* ************************************************************************** */ /* CHANNELS API */ -/* -------------------------- Internal Macros ------------------------------- */ - -/* set/clear/toggle macro - * - channel - channel with a 'flag' member that we're setting - * - smode - 0=clear, 1=set, 2=toggle - * - sflag - bitflag to set - */ -#define ACHANNEL_SET_FLAG(channel, smode, sflag) \ - { \ - if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \ - else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \ - else (channel)->flag &= ~(sflag); \ - } - -/* set/clear/toggle macro, where the flag is negative - * - channel - channel with a 'flag' member that we're setting - * - smode - 0=clear, 1=set, 2=toggle - * - sflag - bitflag to set - */ -#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \ - { \ - if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \ - else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \ - else (channel)->flag |= (sflag); \ - } - /* -------------------------- Exposed API ----------------------------------- */ /* Set the given animation-channel as the active one for the active context */ @@ -149,6 +123,13 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE); } break; + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)ale->data; + + ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); + } + break; } } @@ -167,6 +148,13 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan fcu->flag |= FCURVE_ACTIVE; } break; + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)channel_data; + + ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); + } + break; } } @@ -217,6 +205,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short if (ale->flag & FCURVE_SELECTED) sel= ACHANNEL_SETFLAG_CLEAR; break; + case ANIMTYPE_NLATRACK: + if (ale->flag & NLATRACK_SELECTED) + sel= ACHANNEL_SETFLAG_CLEAR; + break; } } } @@ -263,6 +255,14 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short fcu->flag &= ~FCURVE_ACTIVE; } break; + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)ale->data; + + ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED); + nlt->flag &= ~NLATRACK_ACTIVE; + } + break; } } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index afad396607b..ed526bd99a0 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -195,7 +195,7 @@ static short actedit_get_context (bAnimContext *ac, SpaceAction *saction) } } -/* ----------- Private Stuff - IPO Editor ------------- */ +/* ----------- Private Stuff - Graph Editor ------------- */ /* Get data being edited in Graph Editor (depending on current 'mode') */ static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo) @@ -237,6 +237,26 @@ static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo) } } +/* ----------- Private Stuff - NLA Editor ------------- */ + +/* Get data being edited in Graph Editor (depending on current 'mode') */ +static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla) +{ + /* init dopesheet data if non-existant (i.e. for old files) */ + if (snla->ads == NULL) + snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); + + /* sync settings with current view status, then return appropriate data */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + snla->ads->source= (ID *)ac->scene; + snla->ads->filterflag |= ADS_FILTER_ONLYNLA; + + ac->datatype= ANIMCONT_NLA; + ac->data= snla->ads; + + return 1; +} + /* ----------- Public API --------------- */ /* Obtain current anim-data context, given that context info from Blender context has already been set @@ -264,6 +284,13 @@ short ANIM_animdata_context_getdata (bAnimContext *ac) ok= graphedit_get_context(ac, sipo); } break; + + case SPACE_NLA: + { + SpaceNla *snla= (SpaceNla *)sa->spacedata.first; + ok= nlaedit_get_context(ac, snla); + } + break; } } @@ -313,6 +340,42 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* quick macro to test if AnimData is usable for drivers */ #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first) +/* quick macro to test if AnimData is usable for NLA */ +#define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first) + +/* quick macro to test for all three avove usability tests, performing the appropriate provided + * action for each when the AnimData context is appropriate. + * + * Priority order for this goes (most important, to least): NLA, Drivers, Keyframes + * + * - id: ID block which should have an AnimData pointer following it immediately, to use + * - nlaOk: line or block of code to execute for NLA case + * - driversOk: line or block of code to execute for Drivers case + * - keysOk: line or block of code for Keyframes case + */ +#define ANIMDATA_FILTER_CASES(id, nlaOk, driversOk, keysOk) \ + {\ + if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ + if (ANIMDATA_HAS_NLA(id)) {\ + nlaOk\ + }\ + else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\ + nlaOk\ + }\ + }\ + else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\ + if (ANIMDATA_HAS_DRIVERS(id)) {\ + driversOk\ + }\ + }\ + else {\ + if (ANIMDATA_HAS_KEYS(id)) {\ + keysOk\ + }\ + }\ + } + + /* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \ @@ -494,6 +557,25 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s ale->datatype= ALE_GPFRAME; } break; + + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)data; + + ale->flag= nlt->flag; + + // XXX or should this be done some other way? + ale->key_data= &nlt->strips; + ale->datatype= ALE_NLASTRIP; + } + break; + case ANIMTYPE_NLAACTION: + { + /* nothing to include for now... nothing editable from NLA-perspective here */ + ale->key_data= NULL; + ale->datatype= ALE_NONE; + } + break; } } @@ -522,7 +604,6 @@ static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionG if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) ) { /* only include if this curve is active */ if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) { - /* owner/ownertype will be either object or action-channel, depending if it was dopesheet or part of an action */ ale= make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id); if (ale) { @@ -610,6 +691,55 @@ static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter return items; } +static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id) +{ + bAnimListElem *ale; + NlaTrack *nlt; + int items = 0; + + /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + /* only work with this channel and its subchannels if it is editable */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) { + /* only include this track if selected in a way consistent with the filtering requirements */ + if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) { + /* only include if this track is active */ + // XXX keep this? + if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) { + ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id); + + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + } + } + } + + /* if showing channels, include active action */ + if (filter_mode & ANIMFILTER_CHANNELS) { + /* there isn't really anything editable here, so skip if need editable */ + // TODO: currently, selection isn't checked since it doesn't matter + if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { + /* just add the action track now (this MUST appear for drawing) + * - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then + * overwrite this with the real value - REVIEW THIS... + */ + ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id); + ale->data= (adt->action) ? adt->action : NULL; + + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + } + + /* return the number of items added to the list */ + return items; +} + static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype, ID *owner_id) { bAnimListElem *ale; @@ -752,19 +882,18 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */ for (a=0; a < ob->totcol; a++) { Material *ma= give_current_material(ob, a); + short ok = 0; /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */ if (ELEM(NULL, ma, ma->adt)) continue; - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) { - if (ANIMDATA_HAS_KEYS(ma) == 0) - continue; - } - else { - if (ANIMDATA_HAS_DRIVERS(ma) == 0) - continue; - } + /* check if ok */ + ANIMDATA_FILTER_CASES(ma, + ok=1;, + ok=1;, + ok=1;) + if (ok == 0) continue; /* make a temp list elem for this */ ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache"); @@ -801,16 +930,12 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, } } - /* add material's F-Curve or Driver channels? */ + /* add material's animation data */ if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) { - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) { - // XXX the 'owner' info here is still subject to improvement - items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma); - } - else { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma); - } + ANIMDATA_FILTER_CASES(ma, + items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, + items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, + items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);) } } } @@ -871,15 +996,11 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad /* add object-data animation channels? */ if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* Action or Drivers? */ - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) { - // XXX the 'owner' info here is still subject to improvement - items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat); - } - else { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat); - } + /* filtering for channels - nla, drivers, keyframes */ + ANIMDATA_FILTER_CASES(iat, + items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);, + items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, + items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);) } /* return the number of items added to the list */ @@ -889,8 +1010,10 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; + AnimData *adt = NULL; Object *ob= base->object; Key *key= ob_get_key(ob); + short obdata_ok = 0; int items = 0; /* add this object as a channel first */ @@ -909,73 +1032,81 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & ANIMFILTER_CURVESONLY) ) return items; - /* Action or Drivers */ - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) { - /* Action? */ - if (ANIMDATA_HAS_KEYS(ob) /*&& !(ads->filterflag & ADS_FILTER_NOACTS)*/) { - AnimData *adt= ob->adt; - - /* include action-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* Action, Drivers, or NLA */ + if (ob->adt) { + adt= ob->adt; + ANIMDATA_FILTER_CASES(ob, + { /* nla */ +#if 0 + /* include nla-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLNLA, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } - } - - /* add F-Curve channels? */ - if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); - } - } - } - else { - /* Drivers */ - if (ANIMDATA_HAS_DRIVERS(ob)) { - AnimData *adt= ob->adt; - - /* include drivers-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; +#endif + + /* add NLA tracks */ + items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); + }, + { /* drivers */ + /* include drivers-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add F-Curve channels (drivers are F-Curves) */ + if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { + // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) + items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob); + } + }, + { /* action (keyframes) */ + /* include action-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add F-Curve channels? */ + if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { + // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) + items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); } } - - /* add F-Curve channels (drivers are F-Curves) */ - if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob); - } - } + ) } + /* ShapeKeys? */ if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { - /* Animation or Drivers */ - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) { - /* include shapekey-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + adt= key->adt; + ANIMDATA_FILTER_CASES(key, + { /* nla */ +#if 0 + /* include nla-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLNLA, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } - } - - /* add channels */ - if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); - } - } - else { - /* Drivers */ - if (ANIMDATA_HAS_DRIVERS(key)) { - AnimData *adt= key->adt; +#endif + /* add NLA tracks */ + items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); + }, + { /* drivers */ /* include shapekey-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); @@ -985,15 +1116,28 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B } } - /* add F-Curve channels (drivers are F-Curves) */ - if (FILTER_SKE_OBJD(key)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) { - // XXX owner info is messed up now... - items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)key); + /* add channels */ + if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) { + items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); + } + }, + { /* action (keyframes) */ + /* include shapekey-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add channels */ + if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) { + items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); } } - } + ) } - /* Materials? */ if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) @@ -1006,14 +1150,10 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B Camera *ca= (Camera *)ob->data; if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) { - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) { - if (ANIMDATA_HAS_KEYS(ca)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } - else { - if (ANIMDATA_HAS_DRIVERS(ca)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } + ANIMDATA_FILTER_CASES(ca, + obdata_ok= 1;, + obdata_ok= 1;, + obdata_ok= 1;) } } break; @@ -1022,14 +1162,10 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B Lamp *la= (Lamp *)ob->data; if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) { - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) { - if (ANIMDATA_HAS_KEYS(la)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } - else { - if (ANIMDATA_HAS_DRIVERS(la)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } + ANIMDATA_FILTER_CASES(la, + obdata_ok= 1;, + obdata_ok= 1;, + obdata_ok= 1;) } } break; @@ -1038,18 +1174,16 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B Curve *cu= (Curve *)ob->data; if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) { - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) { - if (ANIMDATA_HAS_KEYS(cu)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } - else { - if (ANIMDATA_HAS_DRIVERS(cu)) - items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); - } + ANIMDATA_FILTER_CASES(cu, + obdata_ok= 1;, + obdata_ok= 1;, + obdata_ok= 1;) } } break; } + if (obdata_ok) + items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode); /* return the number of items added to the list */ return items; @@ -1058,6 +1192,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) { World *wo= sce->world; + AnimData *adt= NULL; bAnimListElem *ale; int items = 0; @@ -1077,74 +1212,80 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & ANIMFILTER_CURVESONLY) ) return items; - /* Action or Drivers */ - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) { - /* Action? */ - if (ANIMDATA_HAS_KEYS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)) { - AnimData *adt= sce->adt; - - /* include action-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* Action, Drivers, or NLA for Scene */ + if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { + adt= sce->adt; + ANIMDATA_FILTER_CASES(sce, + { /* nla */ +#if 0 + /* include nla-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLNLA, base, ANIMTYPE_SCENE (ID *)sce); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } - } - - /* add F-Curve channels? */ - if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { - items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); - } - } - } - else { - /* Drivers */ - if (ANIMDATA_HAS_DRIVERS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)) { - AnimData *adt= sce->adt; - - /* include drivers-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; +#endif + + /* add NLA tracks */ + items += animdata_filter_nla(anim_data, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); + }, + { /* drivers */ + /* include drivers-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add F-Curve channels (drivers are F-Curves) */ + if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { + items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce); + } + }, + { /* action */ + /* include action-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add F-Curve channels? */ + if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { + items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); } } - - /* add F-Curve channels (drivers are F-Curves) */ - if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { - items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce); - } - } + ) } - + /* world */ if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) { - /* Animation or Drivers */ - if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) { - AnimData *adt= wo->adt; - - /* include world-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* Action, Drivers, or NLA for World */ + adt= wo->adt; + ANIMDATA_FILTER_CASES(wo, + { /* nla */ +#if 0 + /* include nla-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLNLA, base, ANIMTYPE_DSWOR (ID *)wo); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } - } - - /* add channels */ - if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); - } - } - else { - /* Drivers */ - if (ANIMDATA_HAS_DRIVERS(wo)) { - AnimData *adt= wo->adt; +#endif - /* include shapekey-expand widget? */ + /* add NLA tracks */ + items += animdata_filter_nla(anim_data, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); + }, + { /* drivers */ + /* include world-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo); if (ale) { @@ -1158,8 +1299,23 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads // XXX owner info is messed up now... items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo); } + }, + { /* action */ + /* include world-expand widget? */ + if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { + ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } + } + + /* add channels */ + if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) { + items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); + } } - } + ) } /* return the number of items added to the list */ @@ -1182,22 +1338,18 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int /* scene-linked animation */ // TODO: sequencer, composite nodes - are we to include those here too? { - short sceOk, worOk; + short sceOk= 0, worOk= 0; /* check filtering-flags if ok */ - if (ads->filterflag) { - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { - sceOk= (ANIMDATA_HAS_DRIVERS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)); - worOk= ((sce->world) && ANIMDATA_HAS_DRIVERS(sce->world) && !(ads->filterflag & ADS_FILTER_NOWOR)); - } - else { - sceOk= (ANIMDATA_HAS_KEYS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)); - worOk= ((sce->world) && ANIMDATA_HAS_KEYS(sce->world) && !(ads->filterflag & ADS_FILTER_NOWOR)); - } - } - else { - sceOk= (ANIMDATA_HAS_KEYS(sce)); - worOk= ((sce->world) && ANIMDATA_HAS_KEYS(sce->world)); + ANIMDATA_FILTER_CASES(sce, + sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, + sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, + sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);) + if (sce->world) { + ANIMDATA_FILTER_CASES(sce->world, + worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, + worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, + worOk= !(ads->filterflag & ADS_FILTER_NOWOR);) } /* check if not all bad (i.e. so there is something to show) */ @@ -1239,13 +1391,19 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int } /* check filters for datatypes */ - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { - actOk= (ANIMDATA_HAS_DRIVERS(ob)); - keyOk= ((key) && ANIMDATA_HAS_DRIVERS(key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)); - } - else { - actOk= ANIMDATA_HAS_KEYS(ob); - keyOk= ((key) && ANIMDATA_HAS_KEYS(key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)); + /* object */ + actOk= 0; + keyOk= 0; + ANIMDATA_FILTER_CASES(ob, + actOk= 1;, + actOk= 1;, + actOk= 1;) + if (key) { + /* shapekeys */ + ANIMDATA_FILTER_CASES(key, + keyOk= 1;, + keyOk= 1;, + keyOk= 1;) } /* materials - only for geometric types */ @@ -1260,18 +1418,13 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int Material *ma= give_current_material(ob, a); /* if material has relevant animation data, break */ - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { - if (ANIMDATA_HAS_DRIVERS(ma)) { - matOk= 1; - break; - } - } - else { - if (ANIMDATA_HAS_KEYS(ma)) { - matOk= 1; - break; - } - } + ANIMDATA_FILTER_CASES(ma, + matOk= 1;, + matOk= 1;, + matOk= 1;) + + if (matOk) + break; } } @@ -1280,19 +1433,21 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int case OB_CAMERA: /* ------- Camera ------------ */ { Camera *ca= (Camera *)ob->data; - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) - dataOk= (ANIMDATA_HAS_DRIVERS(ca) && !(ads->filterflag & ADS_FILTER_NOCAM)); - else - dataOk= (ANIMDATA_HAS_KEYS(ca) && !(ads->filterflag & ADS_FILTER_NOCAM)); + dataOk= 0; + ANIMDATA_FILTER_CASES(ca, + dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);) } break; case OB_LAMP: /* ---------- Lamp ----------- */ { Lamp *la= (Lamp *)ob->data; - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) - dataOk= (ANIMDATA_HAS_DRIVERS(la) && !(ads->filterflag & ADS_FILTER_NOLAM)); - else - dataOk= (ANIMDATA_HAS_KEYS(la) && !(ads->filterflag & ADS_FILTER_NOLAM)); + dataOk= 0; + ANIMDATA_FILTER_CASES(la, + dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, + dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);) } break; default: /* --- other --- */ @@ -1400,6 +1555,7 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode case ANIMCONT_DOPESHEET: case ANIMCONT_FCURVES: case ANIMCONT_DRIVERS: + case ANIMCONT_NLA: items= animdata_filter_dopesheet(anim_data, data, filter_mode); break; } diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index cfbd6d2bced..144cd68f6df 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -412,8 +412,6 @@ void scene_to_keylist(Scene *sce, ListBase *keys, ListBase *blocks, ActKeysInc * /* get filterflag */ if (ads) filterflag= ads->filterflag; - else if ((aki) && (aki->actmode == -1)) /* only set like this by NLA */ - filterflag= ADS_FILTER_NLADUMMY; else filterflag= 0; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index efc0a0b9a57..cdd8b5c368c 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -75,8 +75,9 @@ typedef enum eAnimCont_Types { ANIMCONT_SHAPEKEY, /* shapekey (Key) */ ANIMCONT_GPENCIL, /* grease pencil (screen) */ ANIMCONT_DOPESHEET, /* dopesheet (bDopesheet) */ - ANIMCONT_FCURVES, /* animation F-Curves (bDopesheet) */ // XXX + ANIMCONT_FCURVES, /* animation F-Curves (bDopesheet) */ ANIMCONT_DRIVERS, /* drivers (bDopesheet) */ + ANIMCONT_NLA, /* nla (bDopesheet) */ } eAnimCont_Types; /* --------------- Channels -------------------- */ @@ -92,10 +93,10 @@ typedef struct bAnimListElem { int flag; /* copy of elem's flags for quick access */ int index; /* copy of adrcode where applicable */ - void *key_data; /* motion data - ipo or ipo-curve */ + void *key_data; /* motion data - mostly F-Curves, but can be other types too */ short datatype; /* type of motion data to expect */ - struct ID *id; /* ID block that channel is attached to (may be used */ + struct ID *id; /* ID block that channel is attached to (may be used */ void *owner; /* group or channel which acts as this channel's owner */ short ownertype; /* type of owner */ @@ -128,6 +129,9 @@ typedef enum eAnim_ChannelType { ANIMTYPE_GPDATABLOCK, ANIMTYPE_GPLAYER, + + ANIMTYPE_NLATRACK, + ANIMTYPE_NLAACTION, } eAnim_ChannelType; /* types of keyframe data in bAnimListElem */ @@ -135,6 +139,7 @@ typedef enum eAnim_KeyType { ALE_NONE = 0, /* no keyframe data */ ALE_FCURVE, /* F-Curve */ ALE_GPFRAME, /* Grease Pencil Frames */ + ALE_NLASTRIP, /* NLA Strips */ // XXX the following are for summaries... should these be kept? ALE_SCE, /* Scene summary */ @@ -202,6 +207,10 @@ typedef enum eAnimFilter_Flags { #define EDITABLE_GPL(gpl) ((gpl->flag & GP_LAYER_LOCKED)==0) #define SEL_GPL(gpl) ((gpl->flag & GP_LAYER_ACTIVE) || (gpl->flag & GP_LAYER_SELECT)) +/* NLA only */ +#define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED) +#define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED)==0) + /* -------------- Channel Defines -------------- */ /* channel heights */ @@ -308,10 +317,35 @@ void ANIM_nla_mapping_draw(struct gla2DDrawInfo *di, struct Object *ob, short re /* Apply/Unapply NLA mapping to all keyframes in the nominated IPO block */ void ANIM_nla_mapping_apply_fcurve(struct Object *ob, struct FCurve *fcu, short restore, short only_keys); -/* ------------- xxx macros ----------------------- */ +/* ------------- Utility macros ----------------------- */ +/* checks if the given BezTriple is selected */ #define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT)) +/* set/clear/toggle macro + * - channel - channel with a 'flag' member that we're setting + * - smode - 0=clear, 1=set, 2=toggle + * - sflag - bitflag to set + */ +#define ACHANNEL_SET_FLAG(channel, smode, sflag) \ + { \ + if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \ + else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \ + else (channel)->flag &= ~(sflag); \ + } + +/* set/clear/toggle macro, where the flag is negative + * - channel - channel with a 'flag' member that we're setting + * - smode - 0=clear, 1=set, 2=toggle + * - sflag - bitflag to set + */ +#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \ + { \ + if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \ + else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \ + else (channel)->flag |= (sflag); \ + } + /* --------- anim_deps.c, animation updates -------- */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 3d0de795778..c6277f319bc 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -35,7 +35,6 @@ struct bContext; struct Base; struct View3D; struct bConstraint; -struct bConstraintChannel; struct KeyBlock; struct Lattice; struct Mesh; @@ -72,20 +71,8 @@ void ED_object_base_init_from_view(struct bContext *C, struct Base *base); int object_data_is_libdata(struct Object *ob); /* constraints */ -struct bConstraint *add_new_constraint(short type); -void add_constraint_to_object(struct bConstraint *con, struct Object *ob); - -struct ListBase *get_active_constraints(struct Object *ob); -struct bConstraint *get_active_constraint(struct Object *ob); -struct bConstraintChannel *get_active_constraint_channel(struct Scene *scene, struct Object *ob); - -void object_test_constraints(struct Object *ob); - -void ED_object_constraint_rename(struct Object *ob, struct bConstraint *con, char *oldname); -void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con); -int ED_object_constraint_delete(struct ReportList *reports, struct Object *ob, struct bConstraint *con); -int ED_object_constraint_move_down(struct ReportList *reports, struct Object *ob, struct bConstraint *con); -int ED_object_constraint_move_up(struct ReportList *reports, struct Object *ob, struct bConstraint *con); +struct bConstraint *add_new_constraint (short type); +void add_constraint_to_object (struct bConstraint *con, struct Object *ob); /* editlattice.c */ void mouse_lattice(struct bContext *C, short mval[2], int extend); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 97c2da5297f..cdb29ecf376 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -189,8 +189,6 @@ typedef struct uiLayout uiLayout; #define FTPREVIEW (35<<9) #define NUMABS (36<<9) #define TOGBUT (37<<9) -#define OPTION (38<<9) -#define OPTIONN (39<<9) #define BUTTYPE (63<<9) /* Drawing @@ -581,8 +579,7 @@ uiBlock *uiLayoutFreeBlock(uiLayout *layout); void uiTemplateHeader(uiLayout *layout, struct bContext *C); void uiTemplateHeaderID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop); -uiLayout *uiTemplateModifier(uiLayout *layout, struct PointerRNA *ptr); -uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr); +uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); void uiTemplatePreview(uiLayout *layout, struct ID *id); /* items */ @@ -595,8 +592,8 @@ void uiItemFloatO(uiLayout *layout, char *name, int icon, char *opname, char *pr void uiItemStringO(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value); void uiItemFullO(uiLayout *layout, char *name, int icon, char *idname, struct IDProperty *properties, int context); -void uiItemR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int expand, int slider, int toggle); -void uiItemFullR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int expand, int slider, int toggle); +void uiItemR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int expand, int slider); +void uiItemFullR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int expand, int slider); void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value); void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 4813b695795..50283113b62 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -52,6 +52,8 @@ enum { V2D_COMMONVIEW_STANDARD, /* listview (i.e. Outliner) */ V2D_COMMONVIEW_LIST, + /* stackview (this is basically a list where new items are added at the top) */ + V2D_COMMONVIEW_STACK, /* headers (this is basically the same as listview, but no y-panning) */ V2D_COMMONVIEW_HEADER, /* ui region containing panels */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index e9a886375c3..0b094f0c8dc 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -679,7 +679,7 @@ static void ui_is_but_sel(uiBut *but) value= ui_get_but_val(but); - if(ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) true= 0; + if( but->type==TOGN || but->type==ICONTOGN) true= 0; if( but->bit ) { lvalue= (int)value; @@ -700,12 +700,10 @@ static void ui_is_but_sel(uiBut *but) case TOG3: case BUT_TOGDUAL: case ICONTOG: - case OPTION: if(value!=but->hardmin) push= 1; break; case ICONTOGN: case TOGN: - case OPTIONN: if(value==0.0) push= 1; break; case ROW: @@ -1511,12 +1509,7 @@ int ui_set_but_string(bContext *C, uiBut *but, const char *str) * custom collection too for bones, vertex groups, .. */ ui_rna_ID_collection(C, but, &ptr, &prop); - if(str == NULL || str[0] == '\0') { - memset(&rptr, 0, sizeof(rptr)); - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); - return 11; - } - else if(prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) { + if(prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) { RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); return 1; } @@ -1996,7 +1989,7 @@ void uiBlockEndAlign(uiBlock *block) int ui_but_can_align(uiBut *but) { - return !ELEM3(but->type, LABEL, OPTION, OPTIONN); + return (but->type != LABEL); } static void ui_block_do_align_but(uiBlock *block, uiBut *first, int nr) diff --git a/source/blender/editors/interface/interface_api.c b/source/blender/editors/interface/interface_api.c index 2bbaee857d1..3cb6678133f 100644 --- a/source/blender/editors/interface/interface_api.c +++ b/source/blender/editors/interface/interface_api.c @@ -89,8 +89,7 @@ void RNA_api_ui_layout(StructRNA *srna) parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); RNA_def_property_flag(parm, PROP_REQUIRED); RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); - RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); - RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); + RNA_def_boolean(func, "slider", 0, "", "Use slider for numeric values."); func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); @@ -199,13 +198,9 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block."); func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Modifier data."); + parm= RNA_def_pointer(func, "context", "Context", "", "Current context."); RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Constraint data."); + parm= RNA_def_pointer(func, "data", "AnyType", "", "Modifier data."); RNA_def_property_flag(parm, PROP_REQUIRED); parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); RNA_def_function_return(func, parm); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index ec2f960dd14..ce01bc19856 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -364,7 +364,7 @@ static void ui_apply_but_TOG(bContext *C, uiBlock *block, uiBut *but, uiHandleBu if(value==0.0) push= 1; else push= 0; - if(ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push= !push; + if(but->type==TOGN || but->type==ICONTOGN) push= !push; ui_set_but_val(but, (double)push); if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but); } @@ -566,8 +566,6 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut case ICONTOGN: case TOGN: case BUT_TOGDUAL: - case OPTION: - case OPTIONN: ui_apply_but_TOG(C, block, but, data); break; case ROW: @@ -2674,8 +2672,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event) case ICONTOGN: case TOGN: case BUT_TOGDUAL: - case OPTION: - case OPTIONN: retval= ui_do_but_TOG(C, but, data, event); break; #if 0 diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 7c739adf1b9..16451ec4510 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -268,7 +268,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else if(icon) but= uiDefIconTextButR(block, ICONTOG, 0, icon, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); else - but= uiDefButR(block, OPTION, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); + but= uiDefButR(block, TOG, 0, name, x1, y1, x2, y2, ptr, propname, index, 0, 0, -1, -1, NULL); break; } case PROP_INT: @@ -338,7 +338,7 @@ void uiDefAutoButsRNA(const bContext *C, uiLayout *layout, PointerRNA *ptr) name= (char*)RNA_property_ui_name(prop); uiItemL(uiLayoutColumn(split, 0), name, 0); - uiItemFullR(uiLayoutColumn(split, 0), "", 0, ptr, prop, -1, 0, 0, 0, 0); + uiItemFullR(uiLayoutColumn(split, 0), "", 0, ptr, prop, -1, 0, 0, 0); } RNA_property_collection_end(&iter); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index f4e3a7f2899..f779022ece5 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1830,13 +1830,11 @@ void ui_draw_but(ARegion *ar, uiStyle *style, uiBut *but, rcti *rect) wt= widget_type(UI_WTYPE_NAME); break; case TOGBUT: + wt= widget_type(UI_WTYPE_TOGGLE); + break; case TOG: case TOGN: case TOG3: - wt= widget_type(UI_WTYPE_TOGGLE); - break; - case OPTION: - case OPTIONN: if (!(but->flag & UI_HAS_ICON)) { wt= widget_type(UI_WTYPE_OPTION); but->flag |= UI_TEXT_LEFT; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 1cb58c986d0..f0032809631 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -501,7 +501,10 @@ void ui_theme_init_userdef(void) btheme->tact= btheme->tipo; SETCOL(btheme->tact.strip, 12, 10, 10, 128); SETCOL(btheme->tact.strip_select, 255, 140, 0, 255); - + + /* space nla */ + btheme->tnla= btheme->tact; + /* space file */ /* to have something initialized */ btheme->tfile= btheme->tv3d; @@ -518,20 +521,6 @@ void ui_theme_init_userdef(void) SETCOL(btheme->tfile.scene, 250, 250, 250, 255); - - - /* space nla */ - btheme->tnla= btheme->tv3d; - SETCOL(btheme->tnla.back, 116, 116, 116, 255); - SETCOL(btheme->tnla.text, 0, 0, 0, 255); - SETCOL(btheme->tnla.text_hi, 255, 255, 255, 255); - SETCOL(btheme->tnla.grid, 94, 94, 94, 255); - SETCOL(btheme->tnla.shade1, 172, 172, 172, 255); // sliders - SETCOL(btheme->tnla.shade2, 84, 44, 31, 100); // bar - SETCOL(btheme->tnla.hilite, 17, 27, 60, 100); // bar - SETCOL(btheme->tnla.strip_select, 0xff, 0xff, 0xaa, 255); - SETCOL(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255); - /* space seq */ btheme->tseq= btheme->tv3d; SETCOL(btheme->tseq.back, 116, 116, 116, 255); diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index b363f1f6272..19c95ce7ce0 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -207,6 +207,23 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) } break; + /* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. + * zoom, aspect ratio, and alignment restrictions are set here */ + case V2D_COMMONVIEW_STACK: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_KEEPZOOM|V2D_KEEPASPECT); + v2d->minzoom= v2d->maxzoom= 1.0f; + + /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed= 1; + + /* scroller settings are currently not set here... that is left for regions... */ + } + break; + /* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */ case V2D_COMMONVIEW_HEADER: { @@ -245,14 +262,14 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) v2d->tot.xmin= 0.0f; v2d->tot.xmax= winx; - + v2d->tot.ymax= 0.0f; v2d->tot.ymin= -winy; - + v2d->cur= v2d->tot; } break; - + /* other view types are completely defined using their own settings already */ default: /* we don't do anything here, as settings should be fine, but just make sure that rect */ diff --git a/source/blender/editors/object/editconstraint.c b/source/blender/editors/object/editconstraint.c index b2cf3be6229..d0e487f98c7 100644 --- a/source/blender/editors/object/editconstraint.c +++ b/source/blender/editors/object/editconstraint.c @@ -49,27 +49,17 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_constraint.h" -#include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_object.h" -#include "BKE_report.h" #include "BKE_utildefines.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" #endif -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - #include "ED_object.h" -#include "ED_screen.h" #include "object_intern.h" @@ -599,6 +589,55 @@ void ob_clear_constraints (Scene *scene) BIF_undo_push("Clear Constraint(s)"); } +/* Rename the given constraint + * - con already has the new name + */ +void rename_constraint (Object *ob, bConstraint *con, char *oldname) +{ + bConstraint *tcon; + ListBase *conlist= NULL; + int from_object= 0; + char *channame=""; + + /* get context by searching for con (primitive...) */ + for (tcon= ob->constraints.first; tcon; tcon= tcon->next) { + if (tcon==con) + break; + } + + if (tcon) { + conlist= &ob->constraints; + channame= "Object"; + from_object= 1; + } + else if (ob->pose) { + bPoseChannel *pchan; + + for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { + for (tcon= pchan->constraints.first; tcon; tcon= tcon->next) { + if (tcon==con) + break; + } + if (tcon) + break; + } + + if (tcon) { + conlist= &pchan->constraints; + channame= pchan->name; + } + } + + if (conlist==NULL) { + printf("rename constraint failed\n"); /* should not happen in UI */ + return; + } + + /* first make sure it's a unique name within context */ + unique_constraint_name (con, conlist); +} + + /* ------------- Constraint Sanity Testing ------------------- */ /* checks validity of object pointers, and NULLs, @@ -850,237 +889,3 @@ void childof_const_clearinv (void *conv, void *unused) /* simply clear the matrix */ Mat4One(data->invmat); } - -/***************************** BUTTONS ****************************/ - -/* Rename the given constraint, con already has the new name */ -void ED_object_constraint_rename(Object *ob, bConstraint *con, char *oldname) -{ - bConstraint *tcon; - ListBase *conlist= NULL; - int from_object= 0; - char *channame=""; - - /* get context by searching for con (primitive...) */ - for (tcon= ob->constraints.first; tcon; tcon= tcon->next) { - if (tcon==con) - break; - } - - if (tcon) { - conlist= &ob->constraints; - channame= "Object"; - from_object= 1; - } - else if (ob->pose) { - bPoseChannel *pchan; - - for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { - for (tcon= pchan->constraints.first; tcon; tcon= tcon->next) { - if (tcon==con) - break; - } - if (tcon) - break; - } - - if (tcon) { - conlist= &pchan->constraints; - channame= pchan->name; - } - } - - if (conlist==NULL) { - printf("rename constraint failed\n"); /* should not happen in UI */ - return; - } - - /* first make sure it's a unique name within context */ - unique_constraint_name (con, conlist); -} - - - - -void ED_object_constraint_set_active(Object *ob, bConstraint *con) -{ - ListBase *lb; - bConstraint *origcon= con; - - /* lets be nice and escape if its active already */ - if(con && (con->flag & CONSTRAINT_ACTIVE)) - return ; - - lb= get_active_constraints(ob); - if(lb == NULL) - return; - - for(con= lb->first; con; con= con->next) { - if(con==origcon) con->flag |= CONSTRAINT_ACTIVE; - else con->flag &= ~CONSTRAINT_ACTIVE; - } - - /* make sure ipowin and buttons shows it */ - if(ob->ipowin==ID_CO) { - // XXX allqueue(REDRAWIPO, ID_CO); - // XXX allspace(REMAKEIPO, 0); - // XXX allqueue(REDRAWNLA, 0); - } - // XXX allqueue(REDRAWBUTSOBJECT, 0); -} - -int ED_object_constraint_delete(ReportList *reports, Object *ob, bConstraint *con) -{ - bConstraintChannel *chan; - ListBase *lb; - - /* remove ipo channel */ - lb= NULL; // XXX get_active_constraint_channels(ob, 0); - if(lb) { - chan = NULL; // XXX get_constraint_channel(lb, con->name); - if(chan) { - if(chan->ipo) chan->ipo->id.us--; - BLI_freelinkN(lb, chan); - } - } - - /* remove constraint itself */ - lb= get_active_constraints(ob); - free_constraint_data(con); - BLI_freelinkN(lb, con); - - ED_object_constraint_set_active(ob, NULL); - - return 1; -} - -int ED_object_constraint_move_down(ReportList *reports, Object *ob, bConstraint *constr) -{ - bConstraint *con; - ListBase *conlist; - - if(constr->next) { - conlist = get_active_constraints(ob); - for(con= conlist->first; con; con= con->next) { - if(con==constr) { - BLI_remlink(conlist, con); - BLI_insertlink(conlist, con->next, con); - return 1; - } - } - } - - return 0; -} - -int ED_object_constraint_move_up(ReportList *reports, Object *ob, bConstraint *constr) -{ - bConstraint *con; - ListBase *conlist; - - if(constr->prev) { - conlist = get_active_constraints(ob); - for(con= conlist->first; con; con= con->next) { - if(con==constr) { - BLI_remlink(conlist, con); - BLI_insertlink(conlist, con->prev->prev, con); - return 1; - } - } - } - - return 0; -} - -/***************************** OPERATORS ****************************/ - -/************************ add constraint operator *********************/ - -static int constraint_add_exec(bContext *C, wmOperator *op) -{ - Scene *scene= CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - bConstraint *con; - ListBase *list= get_active_constraints(ob); - bPoseChannel *pchan= get_active_posechannel(ob); - int type= RNA_enum_get(op->ptr, "type"); - - con = add_new_constraint(type); - - if(list) { - unique_constraint_name(con, list); - BLI_addtail(list, con); - - if(proxylocked_constraints_owner(ob, pchan)) - con->flag |= CONSTRAINT_PROXY_LOCAL; - - con->flag |= CONSTRAINT_ACTIVE; - for(con= con->prev; con; con= con->prev) - con->flag &= ~CONSTRAINT_ACTIVE; - } - - switch(type) { - case CONSTRAINT_TYPE_CHILDOF: - { - /* if this constraint is being added to a posechannel, make sure - * the constraint gets evaluated in pose-space */ - if(ob->flag & OB_POSEMODE) { - con->ownspace = CONSTRAINT_SPACE_POSE; - con->flag |= CONSTRAINT_SPACEONCE; - } - } - break; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - { - bRigidBodyJointConstraint *data; - - /* set selected first object as target - moved from new_constraint_data */ - data = (bRigidBodyJointConstraint*)con->data; - - CTX_DATA_BEGIN(C, Object*, selob, selected_objects) { - if(selob != ob) { - data->tar= selob; - break; - } - } - CTX_DATA_END; - } - break; - default: - break; - } - - object_test_constraints(ob); - - if(ob->pose) - update_pose_constraint_flags(ob->pose); - - if(ob->type==OB_ARMATURE) - DAG_object_flush_update(scene, ob, OB_RECALC_DATA|OB_RECALC_OB); - else - DAG_object_flush_update(scene, ob, OB_RECALC_DATA); - - WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); - - return OPERATOR_FINISHED; -} - -void OBJECT_OT_constraint_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Constraint"; - ot->description = "Add a constraint to the active object."; - ot->idname= "OBJECT_OT_constraint_add"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= constraint_add_exec; - - ot->poll= ED_operator_object_active; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", ""); -} - diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index ce8bd7287f7..223f2190f4b 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -88,8 +88,5 @@ void GROUP_OT_objects_remove_active(struct wmOperatorType *ot); void OBJECT_OT_modifier_add(struct wmOperatorType *ot); void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot); -/* editconstraint.c */ -void OBJECT_OT_constraint_add(struct wmOperatorType *ot); - #endif /* ED_OBJECT_INTERN_H */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 2e2c16ee6d6..339d8bc8252 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -368,8 +368,6 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", modifier_type_items, 0, "Type", ""); } -/****************** multires subdivide operator *********************/ - static int multires_subdivide_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 9d8247522e1..f2a020e69a6 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -101,8 +101,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_modifier_add); WM_operatortype_append(OBJECT_OT_multires_subdivide); - - WM_operatortype_append(OBJECT_OT_constraint_add); } void ED_keymap_object(wmWindowManager *wm) diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index d4782418be7..f64cd0f707c 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -174,7 +174,7 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op) deselect_action_keys(&ac, 1, SELECT_ADD); /* set notifier that things have changed */ - ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead! + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); return OPERATOR_FINISHED; } @@ -766,6 +766,7 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode, if (ale == NULL) { /* channel not found */ printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index); + BLI_freelistN(&anim_data); return; } else { diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index cbd1457e562..091319cd402 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -144,6 +144,9 @@ int ED_fileselect_layout_offset(FileLayout* layout, int x, int y) int offsetx, offsety; int active_file; + if (layout == NULL) + return NULL; + offsetx = (x)/(layout->tile_w + 2*layout->tile_border_x); offsety = (y)/(layout->tile_h + 2*layout->tile_border_y); diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 74002f64187..ef42b009bd4 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -192,7 +192,7 @@ static SpaceLink *graph_duplicate(SpaceLink *sl) SpaceIpo *sipon= MEM_dupallocN(sl); /* clear or remove stuff from old */ - //sipon->ipokey.first= sipon->ipokey.last= NULL; + BLI_duplicatelist(&sipon->ghostCurves, &((SpaceIpo *)sl)->ghostCurves); sipon->ads= MEM_dupallocN(sipon->ads); return (SpaceLink *)sipon; diff --git a/source/blender/editors/space_image/image_header.c b/source/blender/editors/space_image/image_header.c index 9a61d3a7081..2accef990d3 100644 --- a/source/blender/editors/space_image/image_header.c +++ b/source/blender/editors/space_image/image_header.c @@ -150,8 +150,8 @@ static void image_viewmenu(bContext *C, uiLayout *layout, void *arg_unused) uiItemS(layout); - uiItemR(layout, NULL, 0, &spaceptr, "update_automatically", 0, 0, 0); - // XXX if(show_uvedit) uiItemR(layout, NULL, 0, &uvptr, "local_view", 0, 0, 0); // "UV Local View", Numpad / + uiItemR(layout, NULL, 0, &spaceptr, "update_automatically", 0, 0); + // XXX if(show_uvedit) uiItemR(layout, NULL, 0, &uvptr, "local_view", 0, 0); // "UV Local View", Numpad / uiItemS(layout); @@ -234,7 +234,7 @@ static void image_imagemenu(bContext *C, uiLayout *layout, void *arg_unused) uiItemS(layout); - uiItemR(layout, NULL, 0, &spaceptr, "image_painting", 0, 0, 0); + uiItemR(layout, NULL, 0, &spaceptr, "image_painting", 0, 0); /* move to realtime properties panel */ RNA_id_pointer_create(&ima->id, &imaptr); @@ -338,12 +338,12 @@ static void image_uvsmenu(bContext *C, uiLayout *layout, void *arg_unused) RNA_id_pointer_create(&scene->id, &sceneptr); /* create menu */ - uiItemR(layout, NULL, 0, &uvptr, "snap_to_pixels", 0, 0, 0); - uiItemR(layout, NULL, 0, &uvptr, "constrain_to_image_bounds", 0, 0, 0); + uiItemR(layout, NULL, 0, &uvptr, "snap_to_pixels", 0, 0); + uiItemR(layout, NULL, 0, &uvptr, "constrain_to_image_bounds", 0, 0); uiItemS(layout); - uiItemR(layout, NULL, 0, &uvptr, "live_unwrap", 0, 0, 0); + uiItemR(layout, NULL, 0, &uvptr, "live_unwrap", 0, 0); uiItemO(layout, NULL, 0, "UV_OT_unwrap"); uiItemBooleanO(layout, "Unpin", 0, "UV_OT_pin", "clear", 1); uiItemO(layout, NULL, 0, "UV_OT_pin"); @@ -363,7 +363,7 @@ static void image_uvsmenu(bContext *C, uiLayout *layout, void *arg_unused) uiItemS(layout); - uiItemR(layout, NULL, 0, &sceneptr, "proportional_editing", 0, 0, 0); + uiItemR(layout, NULL, 0, &sceneptr, "proportional_editing", 0, 0); uiItemMenuEnumR(layout, NULL, 0, &sceneptr, "proportional_editing_falloff"); uiItemS(layout); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c new file mode 100644 index 00000000000..a839ccbf3d6 --- /dev/null +++ b/source/blender/editors/space_nla/nla_channels.c @@ -0,0 +1,444 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * + * Contributor(s): Joshua Leung (major recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include "DNA_listBase.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_world_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_animsys.h" +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "ED_anim_api.h" +#include "ED_keyframes_edit.h" +#include "ED_markers.h" +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "nla_intern.h" // own include + +/* *********************************************** */ +/* Operators for NLA channels-list which need to be different from the standard Animation Editor ones */ + +/* ******************** Borderselect Operator *********************** */ + +static void borderselect_nla_channels (bAnimContext *ac, rcti *rect, short selectmode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + View2D *v2d= &ac->ar->v2d; + rctf rectf; + float ymin=(float)(-NLACHANNEL_HEIGHT), ymax=0; + + /* convert border-region to view coordinates */ + UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax); + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* loop over data, doing border select */ + for (ale= anim_data.first; ale; ale= ale->next) { + ymax= ymin + NLACHANNEL_STEP; + + /* if channel is within border-select region, alter it */ + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) { + /* only the following types can be selected */ + switch (ale->type) { + case ANIMTYPE_OBJECT: /* object */ + { + Base *base= (Base *)ale->data; + Object *ob= base->object; + + ACHANNEL_SET_FLAG(base, selectmode, SELECT); + ACHANNEL_SET_FLAG(ob, selectmode, SELECT); + } + break; + case ANIMTYPE_NLATRACK: /* nla-track */ + { + NlaTrack *nlt= (NlaTrack *)ale->data; + + ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED); + } + break; + } + } + + /* set maximum extent to be the minimum of the next channel */ + ymin= ymax; + } + + /* cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int nlachannels_borderselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + rcti rect; + short selectmode=0; + int event; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get settings from operator */ + rect.xmin= RNA_int_get(op->ptr, "xmin"); + rect.ymin= RNA_int_get(op->ptr, "ymin"); + rect.xmax= RNA_int_get(op->ptr, "xmax"); + rect.ymax= RNA_int_get(op->ptr, "ymax"); + + event= RNA_int_get(op->ptr, "event_type"); + if (event == LEFTMOUSE) // FIXME... hardcoded + selectmode = ACHANNEL_SETFLAG_ADD; + else + selectmode = ACHANNEL_SETFLAG_CLEAR; + + /* apply borderselect animation channels */ + borderselect_nla_channels(&ac, &rect, selectmode); + + return OPERATOR_FINISHED; +} + +void NLA_OT_channels_select_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Border Select"; + ot->idname= "NLA_OT_channels_select_border"; + + /* api callbacks */ + ot->invoke= WM_border_select_invoke; + ot->exec= nlachannels_borderselect_exec; + ot->modal= WM_border_select_modal; + + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* rna */ + RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); +} + +/* ******************** Mouse-Click Operator *********************** */ +/* Depending on the channel that was clicked on, the mouse click will activate whichever + * part of the channel is relevant. + * + * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons + */ + +static void mouse_nla_channels (bAnimContext *ac, float x, int channel_index, short selectmode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get the channel that was clicked on */ + /* filter channels */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); + filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get channel from index */ + ale= BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index); + + BLI_freelistN(&anim_data); + return; + } + + /* action to take depends on what channel we've got */ + switch (ale->type) { + case ANIMTYPE_SCENE: + { + Scene *sce= (Scene *)ale->data; + + if (x < 16) { + /* toggle expand */ + sce->flag ^= SCE_DS_COLLAPSED; + } + else { + /* set selection status */ + if (selectmode == SELECT_INVERT) { + /* swap select */ + sce->flag ^= SCE_DS_SELECTED; + } + else { + sce->flag |= SCE_DS_SELECTED; + } + } + } + break; + case ANIMTYPE_OBJECT: + { + bDopeSheet *ads= (bDopeSheet *)ac->data; + Scene *sce= (Scene *)ads->source; + Base *base= (Base *)ale->data; + Object *ob= base->object; + + if (x < 16) { + /* toggle expand */ + ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX + } + else { + /* set selection status */ + if (selectmode == SELECT_INVERT) { + /* swap select */ + base->flag ^= SELECT; + ob->flag= base->flag; + } + else { + Base *b; + + /* deleselect all */ + for (b= sce->base.first; b; b= b->next) { + b->flag &= ~SELECT; + b->object->flag= b->flag; + } + + /* select object now */ + base->flag |= SELECT; + ob->flag |= SELECT; + } + + /* xxx should be ED_base_object_activate(), but we need context pointer for that... */ + //set_active_base(base); + } + } + break; + case ANIMTYPE_FILLMATD: + { + Object *ob= (Object *)ale->data; + ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX + } + break; + + case ANIMTYPE_DSMAT: + { + Material *ma= (Material *)ale->data; + ma->flag ^= MA_DS_EXPAND; + } + break; + case ANIMTYPE_DSLAM: + { + Lamp *la= (Lamp *)ale->data; + la->flag ^= LA_DS_EXPAND; + } + break; + case ANIMTYPE_DSCAM: + { + Camera *ca= (Camera *)ale->data; + ca->flag ^= CAM_DS_EXPAND; + } + break; + case ANIMTYPE_DSCUR: + { + Curve *cu= (Curve *)ale->data; + cu->flag ^= CU_DS_EXPAND; + } + break; + case ANIMTYPE_DSSKEY: + { + Key *key= (Key *)ale->data; + key->flag ^= KEYBLOCK_DS_EXPAND; + } + break; + case ANIMTYPE_DSWOR: + { + World *wo= (World *)ale->data; + wo->flag ^= WO_DS_EXPAND; + } + break; + + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)ale->data; + + if (x >= (NLACHANNEL_NAMEWIDTH-NLACHANNEL_BUTTON_WIDTH)) { + /* toggle protection (only if there's a toggle there) */ + nlt->flag ^= NLATRACK_PROTECTED; + } + else if (x >= (NLACHANNEL_NAMEWIDTH-2*NLACHANNEL_BUTTON_WIDTH)) { + /* toggle mute */ + nlt->flag ^= NLATRACK_MUTED; + } + else { + /* set selection */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this F-Curve only */ + nlt->flag ^= NLATRACK_SELECTED; + } + else { + /* select F-Curve by itself */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + nlt->flag |= NLATRACK_SELECTED; + } + + /* if NLA-Track is selected now, make NLA-Track the 'active' one in the visible list */ + if (nlt->flag & NLATRACK_SELECTED) + ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + } + } + break; + case ANIMTYPE_NLAACTION: + { + AnimData *adt= BKE_animdata_from_id(ale->owner); /* this won't crash, right? */ + + /* for now, only do something if user clicks on the 'push-down' button */ + if (x >= (NLACHANNEL_NAMEWIDTH-NLACHANNEL_BUTTON_WIDTH)) { + /* activate push-down operator */ + // TODO: make this use the operator instead of calling the function directly + // however, calling the operator requires that we supply the args, and that works with proper buttons only + BKE_nla_action_pushdown(adt); + } + } + break; + + default: + printf("Error: Invalid channel type in mouse_nla_channels() \n"); + } + + /* free channels */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +/* handle clicking */ +static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + bAnimContext ac; + Scene *scene; + ARegion *ar; + View2D *v2d; + int mval[2], channel_index; + short selectmode; + float x, y; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get useful pointers from animation context data */ + scene= ac.scene; + ar= ac.ar; + v2d= &ar->v2d; + + /* get mouse coordinates (in region coordinates) */ + mval[0]= (event->x - ar->winrct.xmin); + mval[1]= (event->y - ar->winrct.ymin); + + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend")) + selectmode= SELECT_INVERT; + else + selectmode= SELECT_REPLACE; + + /* figure out which channel user clicked in + * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height + * so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use + * NLACHANNEL_HEIGHT_HALF. + */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP, 0, (float)NLACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); + + /* handle mouse-click in the relevant channel then */ + mouse_nla_channels(&ac, x, channel_index, selectmode); + + /* set notifier tha things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS); + + return OPERATOR_FINISHED; +} + +void NLA_OT_channels_click (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mouse Click on Channels"; + ot->idname= "NLA_OT_channels_click"; + + /* api callbacks */ + ot->invoke= nlachannels_mouseclick_invoke; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* id-props */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY +} + +/* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c new file mode 100644 index 00000000000..def49021160 --- /dev/null +++ b/source/blender/editors/space_nla/nla_draw.c @@ -0,0 +1,626 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * + * Contributor(s): Joshua Leung (major recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include "DNA_listBase.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_constraint_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_world_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_animsys.h" +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "BIF_gl.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "ED_markers.h" + +#include "nla_intern.h" // own include + +/* XXX */ +extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); +extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); + +/* *********************************************** */ +/* Strips */ + +static void nla_draw_strip (NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc) +{ + /* draw extrapolation info first (as backdrop) */ + // TODO... + + /* draw 'inside' of strip itself */ + /* set color of strip - color is used to indicate status here */ + if (strip->flag & NLASTRIP_FLAG_ACTIVE) { + /* tweaking strip should be drawn green when it is acting as the tweaking strip */ + // FIXME: hardcoded temp-hack colors + glColor3f(0.3f, 0.95f, 0.1f); + } + else if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) { + /* alert user that this strip is also used by the tweaking track (this is set when going into + * 'editmode' for that strip), since the edits made here may not be what the user anticipated + */ + // FIXME: hardcoded temp-hack colors + glColor3f(0.85f, 0.0f, 0.0f); + } + else if (strip->flag & NLASTRIP_FLAG_SELECT) { + /* selected strip - use theme color for selected */ + UI_ThemeColor(TH_STRIP_SELECT); + } + else { + /* normal, unselected strip - use standard strip theme color */ + UI_ThemeColor(TH_STRIP); + } + uiSetRoundBox(15); /* all corners rounded */ + gl_round_box_shade(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1); + + /* draw strip outline */ + if (strip->flag & NLASTRIP_FLAG_ACTIVE) { + /* strip should appear 'sunken', so draw a light border around it */ + glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors + } + else { + /* strip should appear to stand out, so draw a dark border around it */ + glColor3f(0.0f, 0.0f, 0.0f); + } + gl_round_box_shade(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1); +} + +/* ---------------------- */ + +void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + View2D *v2d= &ar->v2d; + float y= 0.0f; + int items, height; + + /* build list of channels to draw */ + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS); + items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* Update max-extent of channels here (taking into account scrollers): + * - this is done to allow the channel list to be scrollable, but must be done here + * to avoid regenerating the list again and/or also because channels list is drawn first + * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for + * start of list offset, and the second is as a correction for the scrollers. + */ + height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2)); + if (height > (v2d->mask.ymax - v2d->mask.ymin)) { + /* don't use totrect set, as the width stays the same + * (NOTE: this is ok here, the configuration is pretty straightforward) + */ + v2d->tot.ymax= (float)(height); + } + + /* loop through channels, and set up drawing depending on their type */ + y= (float)(-NLACHANNEL_FIRST); + + for (ale= anim_data.first; ale; ale= ale->next) { + const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF); + const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF); + + /* check if visible */ + if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) + { + /* data to draw depends on the type of channel */ + switch (ale->type) { + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + /* draw backdrop? */ + // TODO... + + /* draw each strip in the track (if visible) */ + for (strip=nlt->strips.first; strip; strip= strip->next) { + if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) + nla_draw_strip(nlt, strip, v2d, yminc, ymaxc); + } + } + break; + + case ANIMTYPE_NLAACTION: + { + /* just draw a semi-shaded rect spanning the width of the viewable area if there's data */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + if (ale->data) + glColor4f(0.8f, 0.2f, 0.0f, 0.4f); // reddish color - hardcoded for now + else + glColor4f(0.6f, 0.5f, 0.5f, 0.3f); // greyish-red color - hardcoded for now + + glBegin(GL_QUADS); + glVertex2f(v2d->cur.xmin, yminc); + glVertex2f(v2d->cur.xmin, ymaxc); + glVertex2f(v2d->cur.xmax, ymaxc); + glVertex2f(v2d->cur.xmax, yminc); + glEnd(); + + glDisable(GL_BLEND); + } + break; + } + } + + /* adjust y-position for next one */ + y += NLACHANNEL_STEP; + } + + /* free tempolary channels */ + BLI_freelistN(&anim_data); +} + +/* *********************************************** */ +/* Channel List */ + +void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + View2D *v2d= &ar->v2d; + float x= 0.0f, y= 0.0f; + int items, height; + + /* build list of channels to draw */ + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS); + items= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* Update max-extent of channels here (taking into account scrollers): + * - this is done to allow the channel list to be scrollable, but must be done here + * to avoid regenerating the list again and/or also because channels list is drawn first + * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for + * start of list offset, and the second is as a correction for the scrollers. + */ + height= ((items*NLACHANNEL_STEP) + (NLACHANNEL_HEIGHT*2)); + if (height > (v2d->mask.ymax - v2d->mask.ymin)) { + /* don't use totrect set, as the width stays the same + * (NOTE: this is ok here, the configuration is pretty straightforward) + */ + v2d->tot.ymax= (float)(height); + } + + /* loop through channels, and set up drawing depending on their type */ + y= (float)(-NLACHANNEL_FIRST); + + for (ale= anim_data.first; ale; ale= ale->next) { + const float yminc= (float)(y - NLACHANNEL_HEIGHT_HALF); + const float ymaxc= (float)(y + NLACHANNEL_HEIGHT_HALF); + const float ydatac= (float)(y - 7); + + /* check if visible */ + if ( IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) ) + { + short indent= 0, offset= 0, sel= 0, group= 0; + int expand= -1, protect = -1, special= -1, mute = -1; + char name[128]; + + /* determine what needs to be drawn */ + switch (ale->type) { + case ANIMTYPE_SCENE: /* scene */ + { + Scene *sce= (Scene *)ale->data; + + group= 4; + indent= 0; + + special= ICON_SCENE_DATA; + + /* only show expand if there are any channels */ + if (EXPANDED_SCEC(sce)) + expand= ICON_TRIA_UP; + else + expand= ICON_TRIA_RIGHT; + + sel = SEL_SCEC(sce); + strcpy(name, sce->id.name+2); + } + break; + case ANIMTYPE_OBJECT: /* object */ + { + Base *base= (Base *)ale->data; + Object *ob= base->object; + + group= 4; + indent= 0; + + /* icon depends on object-type */ + if (ob->type == OB_ARMATURE) + special= ICON_ARMATURE_DATA; + else + special= ICON_OBJECT_DATA; + + /* only show expand if there are any channels */ + if (EXPANDED_OBJC(ob)) + expand= ICON_TRIA_UP; + else + expand= ICON_TRIA_RIGHT; + + sel = SEL_OBJC(base); + strcpy(name, ob->id.name+2); + } + break; + case ANIMTYPE_FILLMATD: /* object materials (dopesheet) expand widget */ + { + Object *ob = (Object *)ale->data; + + group = 4; + indent = 1; + special = ICON_MATERIAL_DATA; + + if (FILTER_MAT_OBJC(ob)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, "Materials"); + } + break; + + + case ANIMTYPE_DSMAT: /* single material (dopesheet) expand widget */ + { + Material *ma = (Material *)ale->data; + + group = 0; + indent = 0; + special = ICON_MATERIAL_DATA; + offset = 21; + + if (FILTER_MAT_OBJD(ma)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, ma->id.name+2); + } + break; + case ANIMTYPE_DSLAM: /* lamp (dopesheet) expand widget */ + { + Lamp *la = (Lamp *)ale->data; + + group = 4; + indent = 1; + special = ICON_LAMP_DATA; + + if (FILTER_LAM_OBJD(la)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, la->id.name+2); + } + break; + case ANIMTYPE_DSCAM: /* camera (dopesheet) expand widget */ + { + Camera *ca = (Camera *)ale->data; + + group = 4; + indent = 1; + special = ICON_CAMERA_DATA; + + if (FILTER_CAM_OBJD(ca)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, ca->id.name+2); + } + break; + case ANIMTYPE_DSCUR: /* curve (dopesheet) expand widget */ + { + Curve *cu = (Curve *)ale->data; + + group = 4; + indent = 1; + special = ICON_CURVE_DATA; + + if (FILTER_CUR_OBJD(cu)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, cu->id.name+2); + } + break; + case ANIMTYPE_DSSKEY: /* shapekeys (dopesheet) expand widget */ + { + Key *key= (Key *)ale->data; + + group = 4; + indent = 1; + special = ICON_SHAPEKEY_DATA; // XXX + + if (FILTER_SKE_OBJD(key)) + expand = ICON_TRIA_UP; + else + expand = ICON_TRIA_RIGHT; + + //sel = SEL_OBJC(base); + strcpy(name, "Shape Keys"); + } + break; + case ANIMTYPE_DSWOR: /* world (dopesheet) expand widget */ + { + World *wo= (World *)ale->data; + + group = 4; + indent = 1; + special = ICON_WORLD_DATA; + + if (FILTER_WOR_SCED(wo)) + expand = ICON_TRIA_DOWN; + else + expand = ICON_TRIA_RIGHT; + + strcpy(name, wo->id.name+2); + } + break; + + case ANIMTYPE_NLATRACK: /* NLA Track */ + { + NlaTrack *nlt= (NlaTrack *)ale->data; + + indent= 0; + + if (ale->id) { + /* special exception for materials */ + if (GS(ale->id->name) == ID_MA) { + offset= 21; + indent= 1; + } + else + offset= 14; + } + else + offset= 0; + + /* FIXME: 'solo' as the 'special' button? + * - need special icons for these + */ + if (nlt->flag & NLATRACK_SOLO) + special= ICON_LAYER_ACTIVE; + else + special= ICON_LAYER_USED; + + if (nlt->flag & NLATRACK_MUTED) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + + if (EDITABLE_NLT(nlt)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + + sel = SEL_NLT(nlt); + strcpy(name, nlt->name); + } + break; + case ANIMTYPE_NLAACTION: /* NLA Action-Line */ + { + bAction *act= (bAction *)ale->data; + + group = 5; + + if (ale->id) { + /* special exception for materials */ + if (GS(ale->id->name) == ID_MA) { + offset= 21; + indent= 1; + } + else + offset= 14; + } + else + offset= 0; + + special = ICON_ACTION; + + if (act) + sprintf(name, "ActAction: <%s>", act->id.name+2); + else + sprintf(name, "<No Action>"); + } + break; + } + + /* now, start drawing based on this information */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + /* draw backing strip behind channel name */ + if (group == 4) { + /* only used in dopesheet... */ + if (ELEM(ale->type, ANIMTYPE_SCENE, ANIMTYPE_OBJECT)) { + /* object channel - darker */ + UI_ThemeColor(TH_DOPESHEET_CHANNELOB); + uiSetRoundBox((expand == ICON_TRIA_UP)? (8):(1|8)); + gl_round_box(GL_POLYGON, x+offset, yminc, (float)NLACHANNEL_NAMEWIDTH, ymaxc, 10); + } + else { + /* sub-object folders - lighter */ + UI_ThemeColor(TH_DOPESHEET_CHANNELSUBOB); + + offset += 7 * indent; + glBegin(GL_QUADS); + glVertex2f(x+offset, yminc); + glVertex2f(x+offset, ymaxc); + glVertex2f((float)ACHANNEL_NAMEWIDTH, ymaxc); + glVertex2f((float)ACHANNEL_NAMEWIDTH, yminc); + glEnd(); + + /* clear group value, otherwise we cause errors... */ + group = 0; + } + } + else if (group == 5) { + /* Action Line */ + if (ale->data) + glColor3f(0.8f, 0.2f, 0.0f); // reddish color - hardcoded for now + else + glColor3f(0.6f, 0.5f, 0.5f); // greyish-red color - hardcoded for now + + offset += 7 * indent; + uiSetRoundBox((1|2)); // only on top two corners, to show that this channel sits on top of the preceeding ones + gl_round_box(GL_POLYGON, x+offset, yminc, (float)NLACHANNEL_NAMEWIDTH, ymaxc, 8); + + /* clear group value, otherwise we cause errors... */ + group = 0; + } + else { + /* for normal channels + * - use 3 shades of color group/standard color for 3 indention level + */ + UI_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40)); + + indent += group; + offset += 7 * indent; + glBegin(GL_QUADS); + glVertex2f(x+offset, yminc); + glVertex2f(x+offset, ymaxc); + glVertex2f((float)NLACHANNEL_NAMEWIDTH, ymaxc); + glVertex2f((float)NLACHANNEL_NAMEWIDTH, yminc); + glEnd(); + } + + /* draw expand/collapse triangle */ + if (expand > 0) { + UI_icon_draw(x+offset, ydatac, expand); + offset += 17; + } + + /* draw special icon indicating certain data-types */ + if (special > -1) { + /* for normal channels */ + UI_icon_draw(x+offset, ydatac, special); + offset += 17; + } + glDisable(GL_BLEND); + + /* draw name */ + if (sel) + UI_ThemeColor(TH_TEXT_HI); + else + UI_ThemeColor(TH_TEXT); + offset += 3; + UI_DrawString(x+offset, y-4, name); + + /* reset offset - for RHS of panel */ + offset = 0; + + /* set blending again, as text drawing may clear it */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + + /* draw protect 'lock' */ + if (protect > -1) { + offset = 16; + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, protect); + } + + /* draw mute 'eye' */ + if (mute > -1) { + offset += 16; + UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, mute); + } + + /* draw action 'push-down' - only for NLA-Action lines, and only when there's an action */ + if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) { + offset += 16; + + /* XXX firstly draw a little rect to help identify that it's different from the toggles */ + glBegin(GL_LINE_LOOP); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7); + glEnd(); // GL_LINES + + /* now draw the icon */ + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE); + } + + glDisable(GL_BLEND); + } + + /* adjust y-position for next one */ + y += NLACHANNEL_STEP; + } + + /* free tempolary channels */ + BLI_freelistN(&anim_data); +} + +/* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c new file mode 100644 index 00000000000..ce9ae7de7a9 --- /dev/null +++ b/source/blender/editors/space_nla/nla_edit.c @@ -0,0 +1,74 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * + * Contributor(s): Joshua Leung (major recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> + +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_animsys.h" +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_screen.h" + +#include "ED_anim_api.h" +#include "ED_markers.h" +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "nla_intern.h" // own include + +/* *********************************************** */ + +/* *********************************************** */ + +/* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_header.c b/source/blender/editors/space_nla/nla_header.c index 0f6b77da6f5..0dcd3198db0 100644 --- a/source/blender/editors/space_nla/nla_header.c +++ b/source/blender/editors/space_nla/nla_header.c @@ -29,6 +29,10 @@ #include <string.h> #include <stdio.h> +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" #include "DNA_space_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -37,26 +41,36 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" +#include "BKE_animsys.h" +#include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_report.h" #include "BKE_screen.h" - -#include "ED_screen.h" #include "ED_types.h" #include "ED_util.h" -#include "WM_api.h" -#include "WM_types.h" +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_screen.h" #include "BIF_gl.h" -#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" #include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" -#include "nla_intern.h" +#include "ED_markers.h" +/* button events */ +enum { + B_REDR = 0, +} eActHeader_ButEvents; /* ************************ header area region *********************** */ @@ -93,13 +107,17 @@ static uiBlock *dummy_viewmenu(bContext *C, ARegion *ar, void *arg_unused) static void do_nla_buttons(bContext *C, void *arg, int event) { - switch(event) { + switch (event) { + case B_REDR: + ED_area_tag_redraw(CTX_wm_area(C)); + break; } } void nla_header_buttons(const bContext *C, ARegion *ar) { + SpaceNla *snla= (SpaceNla *)CTX_wm_space_data(C); ScrArea *sa= CTX_wm_area(C); uiBlock *block; int xco, yco= 3; @@ -109,7 +127,7 @@ void nla_header_buttons(const bContext *C, ARegion *ar) xco= ED_area_header_standardbuttons(C, block, yco); - if((sa->flag & HEADER_NO_PULLDOWN)==0) { + if ((sa->flag & HEADER_NO_PULLDOWN)==0) { int xmax; xmax= GetButStringLength("View"); @@ -119,7 +137,47 @@ void nla_header_buttons(const bContext *C, ARegion *ar) } uiBlockSetEmboss(block, UI_EMBOSS); - + + /* filtering buttons */ + if (snla->ads) { + uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data"); + uiBlockEndAlign(block); + xco += 5; + + uiBlockBeginAlign(block); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display World Animation"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Materials"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Lamps"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Cameras"); + uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Curves"); + uiBlockEndAlign(block); + xco += 15; + } + else { + // XXX this case shouldn't happen at all... for now, just pad out same amount of space + xco += 7*XIC + 15; + } + xco += (XIC + 8); + + /* auto-snap selector */ + if (snla->flag & SNLA_DRAWTIME) { + uiDefButS(block, MENU, B_REDR, + "Auto-Snap Keyframes %t|No Time-Snap %x0|Nearest Second %x2|Nearest Marker %x3", + xco,yco,90,YIC, &snla->autosnap, 0, 1, 0, 0, + "Auto-snapping mode for times when transforming"); + } + else { + uiDefButS(block, MENU, B_REDR, + "Auto-Snap Keyframes %t|No Time-Snap %x0|Nearest Frame %x2|Nearest Marker %x3", + xco,yco,90,YIC, &snla->autosnap, 0, 1, 0, 0, + "Auto-snapping mode for times when transforming"); + } + xco += 98; + /* always as last */ UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin); diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index c544bd9a408..448b823bd4b 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -17,11 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2008 Blender Foundation. + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung. * All rights reserved. * * - * Contributor(s): Blender Foundation + * Contributor(s): Blender Foundation, Joshua Leung * * ***** END GPL LICENSE BLOCK ***** */ @@ -30,10 +30,63 @@ /* internal exports only */ +/* -------------- NLA Channel Defines -------------- */ +/* NLA channel heights */ +#define NLACHANNEL_FIRST -16 +#define NLACHANNEL_HEIGHT 24 +#define NLACHANNEL_HEIGHT_HALF 12 +#define NLACHANNEL_SKIP 2 +#define NLACHANNEL_STEP (NLACHANNEL_HEIGHT + NLACHANNEL_SKIP) + +/* channel widths */ +#define NLACHANNEL_NAMEWIDTH 200 + +/* channel toggle-buttons */ +#define NLACHANNEL_BUTTON_WIDTH 16 + + +/* **************************************** */ +/* nla_draw.c */ + +void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar); +void draw_nla_channel_list(bAnimContext *ac, SpaceNla *snla, ARegion *ar); + +/* **************************************** */ /* nla_header.c */ + void nla_header_buttons(const bContext *C, ARegion *ar); +/* **************************************** */ +/* nla_select.c */ + +/* defines for left-right select tool */ +enum { + NLAEDIT_LRSEL_TEST = -1, + NLAEDIT_LRSEL_NONE, + NLAEDIT_LRSEL_LEFT, + NLAEDIT_LRSEL_RIGHT, +} eNlaEdit_LeftRightSelect_Mode; + +/* --- */ + +void NLAEDIT_OT_select_all_toggle(wmOperatorType *ot); +void NLAEDIT_OT_click_select(wmOperatorType *ot); + +/* **************************************** */ +/* nla_edit.c */ + +/* **************************************** */ +/* nla_channels.c */ + +void NLA_OT_channels_select_border(wmOperatorType *ot); +void NLA_OT_channels_click(wmOperatorType *ot); + +/* **************************************** */ +/* nla_ops.c */ + +void nla_operatortypes(void); +void nla_keymap(wmWindowManager *wm); #endif /* ED_NLA_INTERN_H */ diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c new file mode 100644 index 00000000000..167686c99f9 --- /dev/null +++ b/source/blender/editors/space_nla/nla_ops.c @@ -0,0 +1,158 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * + * Contributor(s): Joshua Leung (major recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> + +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_animsys.h" +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_screen.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "nla_intern.h" // own include + + +/* ************************** registration - operator types **********************************/ + +void nla_operatortypes(void) +{ + /* channels */ + WM_operatortype_append(NLA_OT_channels_click); + WM_operatortype_append(NLA_OT_channels_select_border); + + /* select */ + WM_operatortype_append(NLAEDIT_OT_click_select); + WM_operatortype_append(NLAEDIT_OT_select_all_toggle); +} + +/* ************************** registration - keymaps **********************************/ + +static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap) +{ + /* NLA-specific (different to standard channels keymap) -------------------------- */ + /* selection */ + /* click-select */ + // XXX for now, only leftmouse.... + WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + + /* borderselect */ + WM_keymap_add_item(keymap, "NLA_OT_channels_select_border", BKEY, KM_PRESS, 0, 0); + + /* General Animation Channels keymap (see anim_channels.c) ----------------------- */ + /* deselect all */ + WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); + + /* settings */ + WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); + WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0); + + /* settings - specialised hotkeys */ + WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0); + + /* expand/collapse */ + WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0); + + RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1); +} + +static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap) +{ + wmKeymapItem *kmi; + + /* selection */ + /* click select */ + WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, 0, 0); + kmi= WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", 1); + kmi= WM_keymap_add_item(keymap, "NLAEDIT_OT_click_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "left_right", NLAEDIT_LRSEL_TEST); + + /* deselect all */ + WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); + + + /* transform system */ + //transform_keymap_for_space(wm, keymap, SPACE_NLA); +} + +/* --------------- */ + +void nla_keymap(wmWindowManager *wm) +{ + ListBase *keymap; + + /* channels */ + /* Channels are not directly handled by the NLA Editor module, but are inherited from the Animation module. + * Most of the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as there + * are many similarities with the other Animation Editors. + * + * However, those operations which involve clicking on channels and/or the placement of them in the view are implemented here instead + */ + keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0); + nla_keymap_channels(wm, keymap); + + /* data */ + keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0); + nla_keymap_main(wm, keymap); +} + diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c new file mode 100644 index 00000000000..5d9fe5f2a05 --- /dev/null +++ b/source/blender/editors/space_nla/nla_select.c @@ -0,0 +1,440 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * + * Contributor(s): Joshua Leung (major recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> + +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_animsys.h" +#include "BKE_nla.h" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_screen.h" + +#include "ED_anim_api.h" +#include "ED_keyframes_edit.h" +#include "ED_markers.h" +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "nla_intern.h" // own include + +/* ******************** Utilities ***************************************** */ + +/* Convert SELECT_* flags to ACHANNEL_SETFLAG_* flags */ +static short selmodes_to_flagmodes (short sel) +{ + /* convert selection modes to selection modes */ + switch (sel) { + case SELECT_SUBTRACT: + return ACHANNEL_SETFLAG_CLEAR; + break; + + case SELECT_INVERT: + return ACHANNEL_SETFLAG_TOGGLE; + break; + + case SELECT_ADD: + default: + return ACHANNEL_SETFLAG_ADD; + break; + } +} + + +/* ******************** Deselect All Operator ***************************** */ +/* This operator works in one of three ways: + * 1) (de)select all (AKEY) - test if select all or deselect all + * 2) invert all (CTRL-IKEY) - invert selection of all keyframes + * 3) (de)select all - no testing is done; only for use internal tools as normal function... + */ + +/* Deselects strips in the NLA Editor + * - This is called by the deselect all operator, as well as other ones! + * + * - test: check if select or deselect all + * - sel: how to select keyframes + * 0 = deselect + * 1 = select + * 2 = invert + */ +static void deselect_nla_strips (bAnimContext *ac, short test, short sel) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + short smode; + + /* determine type-based settings - curvesonly eliminates all the unnecessary channels... */ + filter= (ANIMFILTER_VISIBLE|ANIMFILTER_CURVESONLY); + + /* filter data */ + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* See if we should be selecting or deselecting */ + if (test) { + for (ale= anim_data.first; ale; ale= ale->next) { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + /* if any strip is selected, break out, since we should now be deselecting */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (strip->flag & NLASTRIP_FLAG_SELECT) { + sel= SELECT_SUBTRACT; + break; + } + } + + if (sel == SELECT_SUBTRACT) + break; + } + } + + /* convert selection modes to selection modes */ + smode= selmodes_to_flagmodes(sel); + + /* Now set the flags */ + for (ale= anim_data.first; ale; ale= ale->next) { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + /* apply same selection to all strips */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* set selection */ + ACHANNEL_SET_FLAG(strip, smode, NLASTRIP_FLAG_SELECT); + + /* clear active flag */ + strip->flag &= ~NLASTRIP_FLAG_ACTIVE; + } + } + + /* Cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +static int nlaedit_deselectall_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* 'standard' behaviour - check if selected, then apply relevant selection */ + if (RNA_boolean_get(op->ptr, "invert")) + deselect_nla_strips(&ac, 0, SELECT_INVERT); + else + deselect_nla_strips(&ac, 1, SELECT_ADD); + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + + return OPERATOR_FINISHED; +} + +void NLAEDIT_OT_select_all_toggle (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select All"; + ot->idname= "NLAEDIT_OT_select_all_toggle"; + + /* api callbacks */ + ot->exec= nlaedit_deselectall_exec; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; + + /* props */ + RNA_def_boolean(ot->srna, "invert", 0, "Invert", ""); +} + +/* ******************** Mouse-Click Select Operator *********************** */ +/* This operator works in one of 2 ways: + * 1) Select the strip directly under the mouse + * 2) Select all the strips to one side of the mouse + */ + +/* defines for left-right select tool */ +static EnumPropertyItem prop_nlaedit_leftright_select_types[] = { + {NLAEDIT_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""}, + {NLAEDIT_LRSEL_NONE, "OFF", "Don't select", ""}, + {NLAEDIT_LRSEL_LEFT, "LEFT", "Before current frame", ""}, + {NLAEDIT_LRSEL_RIGHT, "RIGHT", "After current frame", ""}, + {0, NULL, NULL, NULL} +}; + +/* sensitivity factor for frame-selections */ +#define FRAME_CLICK_THRESH 0.1f + + +/* ------------------- */ + +/* option 1) select strip directly under mouse */ +static void mouse_nla_strips (bAnimContext *ac, int mval[2], short select_mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale = NULL; + int filter; + + View2D *v2d= &ac->ar->v2d; + NlaStrip *strip = NULL; + int channel_index; + float xmin, xmax, dummy; + float x, y; + + + /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + UI_view2d_listview_view_to_cell(v2d, 0, NLACHANNEL_STEP, 0, 0, x, y, NULL, &channel_index); + + /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click + * (that is the size of keyframe icons, so user should be expecting similar tolerances) + */ + UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &xmin, &dummy); + UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &xmax, &dummy); + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* try to get channel */ + ale= BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + printf("Error: animation channel (index = %d) not found in mouse_nla_strips() \n", channel_index); + BLI_freelistN(&anim_data); + return; + } + else { + /* found some channel - we only really should do somethign when its an Nla-Track */ + if (ale->type == ANIMTYPE_NLATRACK) { + NlaTrack *nlt= (NlaTrack *)ale->data; + + /* loop over NLA-strips in this track, trying to find one which occurs in the necessary bounds */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) + break; + } + } + + /* remove active channel from list of channels for separate treatment (since it's needed later on) */ + BLI_remlink(&anim_data, ale); + + /* free list of channels, since it's not used anymore */ + BLI_freelistN(&anim_data); + } + + /* for replacing selection, firstly need to clear existing selection */ + if (select_mode == SELECT_REPLACE) { + /* reset selection mode for next steps */ + select_mode = SELECT_ADD; + + /* deselect all strips */ + deselect_nla_strips(ac, 0, SELECT_SUBTRACT); + + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight NLA-Track */ + if (ale->type == ANIMTYPE_NLATRACK) { + NlaTrack *nlt= (NlaTrack *)ale->data; + + nlt->flag |= NLATRACK_SELECTED; + ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + } + } + + /* only select strip if we clicked on a valid channel and hit something */ + if (ale) { + /* select the strip accordingly (if a matching one was found) */ + if (strip) { + select_mode= selmodes_to_flagmodes(select_mode); + ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT); + } + + /* free this channel */ + MEM_freeN(ale); + } +} + +/* Option 2) Selects all the strips on either side of the current frame (depends on which side the mouse is on) */ +static void nlaedit_mselect_leftright (bAnimContext *ac, short leftright, short select_mode) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + Scene *scene= ac->scene; + float xmin, xmax; + + /* if select mode is replace, deselect all keyframes (and channels) first */ + if (select_mode==SELECT_REPLACE) { + select_mode= SELECT_ADD; + + /* deselect all other channels and keyframes */ + ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + deselect_nla_strips(ac, 0, SELECT_SUBTRACT); + } + + /* get range, and get the right flag-setting mode */ + if (leftright == NLAEDIT_LRSEL_LEFT) { + xmin = -MAXFRAMEF; + xmax = (float)(CFRA + FRAME_CLICK_THRESH); + } + else { + xmin = (float)(CFRA - FRAME_CLICK_THRESH); + xmax = MAXFRAMEF; + } + + select_mode= selmodes_to_flagmodes(select_mode); + + + /* filter data */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* select strips on the side where most data occurs */ + for (ale= anim_data.first; ale; ale= ale->next) { + NlaTrack *nlt= (NlaTrack *)ale->data; + NlaStrip *strip; + + /* check each strip to see if it is appropriate */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) { + ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT); + } + } + } + + /* Cleanup */ + BLI_freelistN(&anim_data); +} + +/* ------------------- */ + +/* handle clicking */ +static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + bAnimContext ac; + Scene *scene; + ARegion *ar; + View2D *v2d; + short selectmode; + int mval[2]; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get useful pointers from animation context data */ + scene= ac.scene; + ar= ac.ar; + v2d= &ar->v2d; + + /* get mouse coordinates (in region coordinates) */ + mval[0]= (event->x - ar->winrct.xmin); + mval[1]= (event->y - ar->winrct.ymin); + + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend")) + selectmode= SELECT_INVERT; + else + selectmode= SELECT_REPLACE; + + /* figure out action to take */ + if (RNA_enum_get(op->ptr, "left_right")) { + /* select all keys on same side of current frame as mouse */ + float x; + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL); + if (x < CFRA) + RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_LEFT); + else + RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_RIGHT); + + nlaedit_mselect_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode); + } + else { + /* select strips based upon mouse position */ + mouse_nla_strips(&ac, mval, selectmode); + } + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + + /* for tweak grab to work */ + return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; +} + +void NLAEDIT_OT_click_select (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mouse Select"; + ot->idname= "NLAEDIT_OT_click_select"; + + /* api callbacks - absolutely no exec() this yet... */ + ot->invoke= nlaedit_clickselect_invoke; + ot->poll= ED_operator_areaactive; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* id-props */ + // XXX should we make this into separate operators? + RNA_def_enum(ot->srna, "left_right", prop_nlaedit_leftright_select_types, 0, "Left Right", ""); // CTRLKEY + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY +} + +/* *********************************************** */ diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 6e1a97dea34..024b23c51b8 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -29,6 +29,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_anim_types.h" #include "DNA_nla_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" @@ -41,10 +42,16 @@ #include "BLI_arithb.h" #include "BLI_rand.h" +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_nla.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_screen.h" +#include "BKE_utildefines.h" +#include "ED_anim_api.h" +#include "ED_markers.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -57,8 +64,6 @@ #include "UI_resources.h" #include "UI_view2d.h" -#include "ED_markers.h" - #include "nla_intern.h" // own include /* ******************** default callbacks for nla space ***************** */ @@ -71,6 +76,9 @@ static SpaceLink *nla_new(const bContext *C) snla= MEM_callocN(sizeof(SpaceNla), "initnla"); snla->spacetype= SPACE_NLA; + /* allocate DopeSheet data for NLA Editor */ + snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); + /* header */ ar= MEM_callocN(sizeof(ARegion), "header for nla"); @@ -78,13 +86,15 @@ static SpaceLink *nla_new(const bContext *C) ar->regiontype= RGN_TYPE_HEADER; ar->alignment= RGN_ALIGN_BOTTOM; - /* channel list region XXX */ - ar= MEM_callocN(sizeof(ARegion), "area region from do_versions"); + /* channel list region */ + ar= MEM_callocN(sizeof(ARegion), "channel list for nla"); BLI_addtail(&snla->regionbase, ar); ar->regiontype= RGN_TYPE_CHANNELS; ar->alignment= RGN_ALIGN_LEFT; - ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); + /* only need to set these settings since this will use the 'stack' configuration */ + ar->v2d.scroll = V2D_SCROLL_BOTTOM; + ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; /* main area */ ar= MEM_callocN(sizeof(ARegion), "main area for nla"); @@ -95,12 +105,12 @@ static SpaceLink *nla_new(const bContext *C) ar->v2d.tot.xmin= 1.0f; ar->v2d.tot.ymin= 0.0f; ar->v2d.tot.xmax= 1000.0f; - ar->v2d.tot.ymax= 1000.0f; + ar->v2d.tot.ymax= 500.0f; ar->v2d.cur.xmin= -5.0f; ar->v2d.cur.ymin= 0.0f; ar->v2d.cur.xmax= 65.0f; - ar->v2d.cur.ymax= 1000.0f; + ar->v2d.cur.ymax= 250.0f; ar->v2d.min[0]= 0.0f; ar->v2d.min[1]= 0.0f; @@ -111,10 +121,11 @@ static SpaceLink *nla_new(const bContext *C) ar->v2d.minzoom= 0.1f; ar->v2d.maxzoom= 50.0f; - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom= V2D_LOCKZOOM_Y; - + ar->v2d.align= V2D_ALIGN_NO_NEG_Y; + ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; return (SpaceLink *)snla; } @@ -122,15 +133,25 @@ static SpaceLink *nla_new(const bContext *C) /* not spacelink itself */ static void nla_free(SpaceLink *sl) { -// SpaceNla *snla= (SpaceNla*) sl; + SpaceNla *snla= (SpaceNla*) sl; + if (snla->ads) { + BLI_freelistN(&snla->ads->chanbase); + MEM_freeN(snla->ads); + } } /* spacetype; init callback */ static void nla_init(struct wmWindowManager *wm, ScrArea *sa) { + SpaceNla *snla= (SpaceNla *)sa->spacedata.first; + + /* init dopesheet data if non-existant (i.e. for old files) */ + if (snla->ads == NULL) + snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); + ED_area_tag_refresh(sa); } static SpaceLink *nla_duplicate(SpaceLink *sl) @@ -138,15 +159,31 @@ static SpaceLink *nla_duplicate(SpaceLink *sl) SpaceNla *snlan= MEM_dupallocN(sl); /* clear or remove stuff from old */ + snlan->ads= MEM_dupallocN(snlan->ads); return (SpaceLink *)snlan; } +/* add handlers, stuff you only do once or on area/region changes */ +static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar) +{ + ListBase *keymap; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STACK, ar->winx, ar->winy); + + /* own keymap */ + // TODO: cannot use generic copy, need special NLA version + keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0); /* XXX weak? */ + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +} + +/* draw entirely, view changes should be handled here */ static void nla_channel_area_draw(const bContext *C, ARegion *ar) { - /* draw entirely, view changes should be handled here */ - // SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C); - // View2D *v2d= &ar->v2d; + SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C); + bAnimContext ac; + View2D *v2d= &ar->v2d; + View2DScrollers *scrollers; float col[3]; /* clear and setup matrix */ @@ -154,15 +191,20 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar) glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); - // UI_view2d_view_ortho(C, v2d); - - /* data... */ + UI_view2d_view_ortho(C, v2d); + /* data */ + if (ANIM_animdata_get_context(C, &ac)) { + draw_nla_channel_list(&ac, snla, ar); + } /* reset view matrix */ - //UI_view2d_view_restore(C); + UI_view2d_view_restore(C); - /* scrollers? */ + /* scrollers */ + scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); } @@ -174,16 +216,20 @@ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "NLA", SPACE_NLA, 0); /* XXX weak? */ + keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0); /* XXX weak? */ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } static void nla_main_area_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ - // SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C); + SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C); + bAnimContext ac; View2D *v2d= &ar->v2d; + View2DGrid *grid; + View2DScrollers *scrollers; float col[3]; + short unit=0, flag=0; /* clear and setup matrix */ UI_GetThemeColor3fv(TH_BACK, col); @@ -191,25 +237,40 @@ static void nla_main_area_draw(const bContext *C, ARegion *ar) glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(C, v2d); - - /* data... */ + /* time grid */ + unit= (snla->flag & SNLA_DRAWTIME)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES; + grid= UI_view2d_grid_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy); + UI_view2d_grid_draw(C, v2d, grid, V2D_GRIDLINES_ALL); + UI_view2d_grid_free(grid); + + /* data */ + if (ANIM_animdata_get_context(C, &ac)) { + draw_nla_main_data(&ac, snla, ar); + } + + /* current frame */ + if (snla->flag & SNLA_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS; + if ((snla->flag & SNLA_NODRAWCFRANUM)==0) flag |= DRAWCFRA_SHOW_NUMBOX; + ANIM_draw_cfra(C, v2d, flag); + + /* markers */ + UI_view2d_view_orthoSpecial(C, v2d, 1); + draw_markers_time(C, 0); + + /* preview range */ + UI_view2d_view_ortho(C, v2d); + ANIM_draw_previewrange(C, v2d); /* reset view matrix */ UI_view2d_view_restore(C); - /* scrollers? */ + /* scrollers */ + scrollers= UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); } -void nla_operatortypes(void) -{ - -} - -void nla_keymap(struct wmWindowManager *wm) -{ - -} /* add handlers, stuff you only do once or on area/region changes */ static void nla_header_area_init(wmWindowManager *wm, ARegion *ar) @@ -242,6 +303,82 @@ static void nla_header_area_draw(const bContext *C, ARegion *ar) static void nla_main_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ + switch(wmn->category) { + case NC_SCENE: + switch(wmn->data) { + case ND_OB_ACTIVE: + case ND_FRAME: + case ND_MARKERS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch(wmn->data) { + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + case ND_TRANSFORM: + ED_region_tag_redraw(ar); + break; + } + break; + default: + if(wmn->data==ND_KEYS) + ED_region_tag_redraw(ar); + } +} + +static void nla_channel_area_listener(ARegion *ar, wmNotifier *wmn) +{ + /* context changes */ + switch(wmn->category) { + case NC_SCENE: + switch(wmn->data) { + case ND_OB_ACTIVE: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch(wmn->data) { + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_KEYS: + ED_region_tag_redraw(ar); + break; + } + break; + default: + if(wmn->data==ND_KEYS) + ED_region_tag_redraw(ar); + } +} + +/* editor level listener */ +static void nla_listener(ScrArea *sa, wmNotifier *wmn) +{ + /* context changes */ + switch (wmn->category) { + case NC_SCENE: + /*switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_OB_SELECT: + ED_area_tag_refresh(sa); + break; + }*/ + ED_area_tag_refresh(sa); + break; + case NC_OBJECT: + /*switch (wmn->data) { + case ND_BONE_SELECT: + case ND_BONE_ACTIVE: + ED_area_tag_refresh(sa); + break; + }*/ + ED_area_tag_refresh(sa); + break; + } } /* only called once, from space/spacetypes.c */ @@ -257,6 +394,7 @@ void ED_spacetype_nla(void) st->init= nla_init; st->duplicate= nla_duplicate; st->operatortypes= nla_operatortypes; + st->listener= nla_listener; st->keymap= nla_keymap; /* regions: main window */ @@ -265,7 +403,7 @@ void ED_spacetype_nla(void) art->init= nla_main_area_init; art->draw= nla_main_area_draw; art->listener= nla_main_area_listener; - art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES; + art->keymapflag= ED_KEYMAP_VIEW2D/*|ED_KEYMAP_MARKERS*/|ED_KEYMAP_ANIMATION|ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -286,8 +424,9 @@ void ED_spacetype_nla(void) art->minsizex= 200; art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D; - //art->init= nla_channel_area_init; + art->init= nla_channel_area_init; art->draw= nla_channel_area_draw; + art->listener= nla_channel_area_listener; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 70f90a1a9d9..3b3fd5109cf 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -393,7 +393,6 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn) case ND_GEOM_DATA: case ND_DRAW: case ND_MODIFIER: - case ND_CONSTRAINT: case ND_KEYS: ED_region_tag_redraw(ar); break; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 2d623c9c33d..5b8de93b542 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -3359,7 +3359,7 @@ static void view3d_edit_curvemenu(bContext *C, uiLayout *layout, void *arg_unuse uiItemS(layout); - uiItemR(layout, NULL, 0, &sceneptr, "proportional_editing", 0, 0, 0); // |O + uiItemR(layout, NULL, 0, &sceneptr, "proportional_editing", 0, 0); // |O uiItemMenuEnumR(layout, NULL, 0, &sceneptr, "proportional_editing_falloff"); uiItemS(layout); @@ -4533,12 +4533,12 @@ static void view3d_sculpt_menu(bContext *C, uiLayout *layout, void *arg_unused) RNA_pointer_create(&sc->id, &RNA_Sculpt, s, &rna); - uiItemR(layout, NULL, 0, &rna, "symmetry_x", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "symmetry_y", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "symmetry_z", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "lock_x", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "lock_y", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "lock_z", 0, 0, 0); + uiItemR(layout, NULL, 0, &rna, "symmetry_x", 0, 0); + uiItemR(layout, NULL, 0, &rna, "symmetry_y", 0, 0); + uiItemR(layout, NULL, 0, &rna, "symmetry_z", 0, 0); + uiItemR(layout, NULL, 0, &rna, "lock_x", 0, 0); + uiItemR(layout, NULL, 0, &rna, "lock_y", 0, 0); + uiItemR(layout, NULL, 0, &rna, "lock_z", 0, 0); /* Brush settings */ RNA_pointer_create(&sc->id, &RNA_Brush, s->brush, &rna); @@ -4551,12 +4551,12 @@ static void view3d_sculpt_menu(bContext *C, uiLayout *layout, void *arg_unused) uiItemS(layout); - uiItemR(layout, NULL, 0, &rna, "airbrush", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "rake", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "anchored", 0, 0, 0); - uiItemR(layout, NULL, 0, &rna, "space", 0, 0, 0); + uiItemR(layout, NULL, 0, &rna, "airbrush", 0, 0); + uiItemR(layout, NULL, 0, &rna, "rake", 0, 0); + uiItemR(layout, NULL, 0, &rna, "anchored", 0, 0); + uiItemR(layout, NULL, 0, &rna, "space", 0, 0); - uiItemR(layout, NULL, 0, &rna, "flip_direction", 0, 0, 0); + uiItemR(layout, NULL, 0, &rna, "flip_direction", 0, 0); } uiBlock *view3d_sculptmenu(bContext *C, ARegion *ar, void *arg_unused) diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 7e54045b5e4..e41ab5ac492 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -288,8 +288,10 @@ typedef struct bDopeSheet { /* DopeSheet filter-flag */ typedef enum DOPESHEET_FILTERFLAG { /* general filtering */ - ADS_FILTER_ONLYSEL = (1<<0), - ADS_FILTER_ONLYDRIVERS = (1<<1), + ADS_FILTER_ONLYSEL = (1<<0), /* only include channels relating to selected data */ + + ADS_FILTER_ONLYDRIVERS = (1<<1), /* for 'Drivers' editor - only include Driver data from AnimData */ + ADS_FILTER_ONLYNLA = (1<<2), /* for 'NLA' editor - only include NLA data from AnimData */ /* datatype-based filtering */ ADS_FILTER_NOSHAPEKEYS = (1<<6), @@ -300,9 +302,11 @@ typedef enum DOPESHEET_FILTERFLAG { ADS_FILTER_NOWOR = (1<<14), ADS_FILTER_NOSCE = (1<<15), + /* NLA-specific filters */ + ADS_FILTER_NLA_NOACT = (1<<20), /* if the AnimData block has no NLA data, don't include to just show Action-line */ + /* combination filters (some only used at runtime) */ ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR), - ADS_FILTER_NLADUMMY = (ADS_FILTER_NOSHAPEKEYS|ADS_FILTER_NOOBDATA), } DOPESHEET_FILTERFLAG; /* DopeSheet general flags */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index bf6b9bed5a1..ffc1561e7ab 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -386,85 +386,93 @@ typedef struct AnimMapper { /* ************************************************ */ /* NLA - Non-Linear Animation */ -// TODO: the concepts here still need to be refined to solve any unresolved items - -/* NLA Modifiers ---------------------------------- */ - -/* These differ from F-Curve modifiers, as although F-Curve modifiers also operate on a - * per-channel basis too (in general), they are part of the animation data itself, which - * means that their effects are inherited by all of their users. In order to counteract this, - * the modifiers here should be used to provide variation to pre-created motions only. - */ /* NLA Strips ------------------------------------- */ /* NLA Strip (strip) * * A NLA Strip is a container for the reuse of Action data, defining parameters - * to control the remapping of the Action data to some destination. Actions being - * referenced by NLA-Strips SHOULD-NOT be editable, unless they were created in such - * a way that results in very little mapping distortion (i.e. for layered animation only, - * opposed to prebuilt 'blocks' which are quickly dumped into the NLA for crappymatic machima-type - * stuff) + * to control the remapping of the Action data to some destination. */ typedef struct NlaStrip { struct NlaStrip *next, *prev; - bAction *act; /* Action that is referenced by this strip */ + bAction *act; /* Action that is referenced by this strip (strip is 'user' of the action) */ AnimMapper *remap; /* Remapping info this strip (for tweaking correspondance of action with context) */ - ListBase modifiers; /* NLA Modifiers */ - - ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */ + ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */ // TODO: move out? + ListBase modifiers; /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */ float influence; /* Influence of strip */ - float act_time; /* Current 'time' within action being used */ + float strip_time; /* Current 'time' within action being used (automatically evaluated, but can be overridden) */ float start, end; /* extents of the strip */ float actstart, actend; /* range of the action to use */ - float repeat; /* The number of times to repeat the action range (only when no F-Curves) */ - float scale; /* The amount the action range is scaled by (only when no F-Curves) */ + float repeat; /* The number of times to repeat the action range (only when no F-Curves) */ + float scale; /* The amount the action range is scaled by (only when no F-Curves) */ float blendin, blendout; /* strip blending length (only used when there are no F-Curves) */ - int blendmode; /* strip blending mode */ - - int flag; /* settings */ - - // umm... old unused cruft? - int stride_axis; /* axis for stridebone stuff - 0=x, 1=y, 2=z */ - int pad; - - float actoffs; /* Offset within action, for cycles and striding (only set for ACT_USESTRIDE) */ - float stridelen; /* The stridelength (considered when flag & ACT_USESTRIDE) */ + short blendmode; /* strip blending mode (layer-based mixing) */ + short extendmode; /* strip extrapolation mode (time-based mixing) */ - char stridechannel[32]; /* Instead of stridelen, it uses an action channel */ - char offs_bone[32]; /* if repeat, use this bone/channel for defining offset */ + short flag; /* settings */ + short type; /* type of NLA strip */ } NlaStrip; /* NLA Strip Blending Mode */ enum { - NLASTRIPMODE_BLEND = 0, - NLASTRIPMODE_ADD, - NLASTRIPMODE_SUBTRACT, -} eActStrip_Mode; + NLASTRIP_MODE_BLEND = 0, + NLASTRIP_MODE_ADD, + NLASTRIP_MODE_SUBTRACT, + NLASTRIP_MODE_MULTIPLY, +} eNlaStrip_Blend_Mode; + +/* NLA Strip Extrpolation Mode */ +enum { + /* extend before first frame if no previous strips in track, and always hold+extend last frame */ + NLASTRIP_EXTEND_HOLD = 0, + /* only hold+extend last frame */ + NLASTRIP_EXTEND_HOLD_FORWARD, + /* don't contribute at all */ + NLASTRIP_EXTEND_NOTHING, +} eNlaStrip_Extrapolate_Mode; /* NLA Strip Settings */ -// TODO: check on which of these are still useful... enum { - NLASTRIP_SELECT = (1<<0), - NLASTRIP_USESTRIDE = (1<<1), - NLASTRIP_BLENDTONEXT = (1<<2), /* Not implemented. Is not used anywhere */ - NLASTRIP_HOLDLASTFRAME = (1<<3), - NLASTRIP_ACTIVE = (1<<4), - NLASTRIP_LOCK_ACTION = (1<<5), - NLASTRIP_MUTE = (1<<6), - NLASTRIP_REVERSE = (1<<7), /* This has yet to be implemented. To indicate that a strip should be played backwards */ - NLASTRIP_CYCLIC_USEX = (1<<8), - NLASTRIP_CYCLIC_USEY = (1<<9), - NLASTRIP_CYCLIC_USEZ = (1<<10), - NLASTRIP_AUTO_BLENDS = (1<<11), - NLASTRIP_TWEAK = (1<<12), /* This strip is a tweaking strip (only set if owner track is a tweak track) */ -} eActionStrip_Flag; + /* UI selection flags */ + /* NLA strip is the active one in the track (also indicates if strip is being tweaked) */ + NLASTRIP_FLAG_ACTIVE = (1<<0), + /* NLA strip is selected for editing */ + NLASTRIP_FLAG_SELECT = (1<<1), +// NLASTRIP_FLAG_SELECT_L = (1<<2), // left handle selected +// NLASTRIP_FLAG_SELECT_R = (1<<3), // right handle selected + /* NLA strip uses the same action that the action being tweaked uses (not set for the twaking one though) */ + NLASTRIP_FLAG_TWEAKUSER = (1<<4), + + /* controls driven by local F-Curves */ + /* strip influence is controlled by local F-Curve */ + NLASTRIP_FLAG_USR_INFLUENCE = (1<<5), + NLASTRIP_FLAG_USR_TIME = (1<<6), + + /* playback flags (may be overriden by F-Curves) */ + /* NLA strip blendin/out values are set automatically based on overlaps */ + NLASTRIP_FLAG_AUTO_BLENDS = (1<<10), + /* NLA strip is played back in reverse order */ + NLASTRIP_FLAG_REVERSE = (1<<11), + /* NLA strip is muted (i.e. doesn't contribute in any way) */ + // TODO: this overlaps a lot with the functionality in track + NLASTRIP_FLAG_MUTED = (1<<12), + /* NLA strip length is synced to the length of the referenced action */ + NLASTRIP_FLAG_SYNC_LENGTH = (1<<13), +} eNlaStrip_Flag; + +/* NLA Strip Type */ +enum { + /* 'clip' - references an Action */ + NLASTRIP_TYPE_CLIP = 0, + /* 'transition' - blends between the adjacent strips */ + NLASTRIP_TYPE_TRANSITION, +} eNlaStrip_Type; /* NLA Tracks ------------------------------------- */ @@ -483,14 +491,12 @@ typedef struct NlaTrack { int flag; /* settings for this track */ int index; /* index of the track in the stack (NOTE: not really useful, but we need a pad var anyways!) */ - char info[64]; /* short user-description of this track */ + char name[64]; /* short user-description of this track */ } NlaTrack; /* settings for track */ enum { - /* track is the one that settings can be modified on (doesn't indicate - * that it's for 'tweaking' though) - */ + /* track is the one that settings can be modified on, also indicates if track is being 'tweaked' */ NLATRACK_ACTIVE = (1<<0), /* track is selected in UI for relevant editing operations */ NLATRACK_SELECTED = (1<<1), @@ -500,10 +506,6 @@ enum { NLATRACK_SOLO = (1<<3), /* track's settings (and strips) cannot be edited (to guard against unwanted changes) */ NLATRACK_PROTECTED = (1<<4), - /* strip is the 'last' one that should be evaluated, as the active action - * is being used to tweak the animation of the strips up to here - */ - NLATRACK_TWEAK = (1<<5), } eNlaTrack_Flag; @@ -676,11 +678,13 @@ enum { ADT_NLA_SOLO_TRACK = (1<<0), /* don't use NLA */ ADT_NLA_EVAL_OFF = (1<<1), - /* don't execute drivers */ - ADT_DRIVERS_DISABLED = (1<<2), + /* NLA is being 'tweaked' (i.e. in EditMode) */ + ADT_NLA_EDIT_ON = (1<<2), /* drivers expanded in UI */ ADT_DRIVERS_COLLAPSED = (1<<10), + /* don't execute drivers */ + ADT_DRIVERS_DISABLED = (1<<11), } eAnimData_Flag; /* Animation Data recalculation settings (to be set by depsgraph) */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 8cdb51bcab0..ba4ef1f164a 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -244,10 +244,11 @@ typedef struct SpaceNla { short blockhandler[8]; - short menunr, lock; short autosnap; /* this uses the same settings as autosnap for Action Editor */ short flag; + int pad; + struct bDopeSheet *ads; View2D v2d; /* depricated, copied to region */ } SpaceNla; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index c679d9fc544..2262c73a9af 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -33,7 +33,6 @@ extern EnumPropertyItem prop_mode_items[]; extern EnumPropertyItem space_type_items[]; extern EnumPropertyItem region_type_items[]; extern EnumPropertyItem modifier_type_items[]; -extern EnumPropertyItem constraint_type_items[]; extern EnumPropertyItem beztriple_handle_type_items[]; extern EnumPropertyItem beztriple_interpolation_mode_items[]; diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 02429ffa4bf..b0b9e2079f1 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1558,4 +1558,4 @@ void RNA_def_constraint(BlenderRNA *brna) rna_def_constraint_shrinkwrap(brna); } -#endif
\ No newline at end of file +#endif diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6baf5083d31..32af373862b 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -49,7 +49,7 @@ static void rna_Object_update(bContext *C, PointerRNA *ptr) DAG_object_flush_update(CTX_data_scene(C), ptr->id.data, OB_RECALC_OB); } -static void rna_Object_dependency_update(bContext *C, PointerRNA *ptr) +static void rna_Object_scene_update(bContext *C, PointerRNA *ptr) { DAG_object_flush_update(CTX_data_scene(C), ptr->id.data, OB_RECALC_OB); DAG_scene_sort(CTX_data_scene(C)); @@ -774,7 +774,7 @@ static StructRNA *rna_def_object(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "transflag"); RNA_def_property_enum_items(prop, dupli_items); RNA_def_property_ui_text(prop, "Dupli Type", "If not None, object duplication method to use."); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_dependency_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_scene_update"); prop= RNA_def_property(srna, "dupli_frames_no_speed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLINOSPEED); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 8edcc4c72f4..5aad710c712 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -82,6 +82,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_struct_idproperties_func(srna, "rna_PoseChannel_idproperties"); prop= RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "constraints", NULL); RNA_def_property_struct_type(prop, "Constraint"); RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel."); diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c index c6515385757..2aeb1b984fb 100644 --- a/source/blender/makesrna/intern/rna_sound.c +++ b/source/blender/makesrna/intern/rna_sound.c @@ -64,30 +64,30 @@ static void rna_def_sample(BlenderRNA *brna) prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_sample_type_items); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); RNA_def_property_ui_text(prop, "Types", ""); prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "name"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); RNA_def_property_ui_text(prop, "Filename", "Full path filename of the sample"); prop= RNA_def_property(srna, "length", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "len"); RNA_def_property_ui_text(prop, "Length", "The length of sample in seconds"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); prop= RNA_def_property(srna, "rate", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "Rate", "Sample rate in kHz"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); prop= RNA_def_property(srna, "bits", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "Bits", "Bit-depth of sample"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); prop= RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "Channels", "Number of channels (mono=1; stereo=2)"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); } static void rna_def_soundlistener(BlenderRNA *brna) @@ -117,12 +117,12 @@ static void rna_def_soundlistener(BlenderRNA *brna) prop= RNA_def_property(srna, "num_sounds_blender", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "numsoundsblender"); RNA_def_property_ui_text(prop, "Total Sounds in Blender", "The total number of sounds currently linked and available."); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); prop= RNA_def_property(srna, "num_sounds_gameengine", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "numsoundsgameengine"); RNA_def_property_ui_text(prop, "Total Sounds in Game Engine", "The total number of sounds in the Game Engine."); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NOT_EDITABLE); } #endif diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 9d3d961c18f..e1bc0de245a 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -151,7 +151,7 @@ static StructRNA *rna_Panel_register(const bContext *C, ReportList *reports, voi PanelType *pt, dummypt = {0}; Panel dummypanel= {0}; PointerRNA dummyptr; - int have_function[3]; + int have_function[2]; /* setup dummy panel & panel type to store static properties in */ dummypanel.type= &dummypt; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 09b81d69ac0..b96089a05f1 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -196,7 +196,6 @@ typedef struct wmNotifier { #define ND_MODIFIER (23<<16) #define ND_KEYS (24<<16) #define ND_GEOM_DATA (25<<16) -#define ND_CONSTRAINT (26<<16) /* NC_MATERIAL Material */ #define ND_SHADING (30<<16) |