diff options
Diffstat (limited to 'source/blender')
62 files changed, 2425 insertions, 832 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 57f8c83eda6..fba09ee9826 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -215,5 +215,6 @@ void BLF_dir_free(char **dirs, int count); // XXX, bad design extern int blf_mono_font; extern int blf_mono_font_render; // dont mess drawing with render threads. +extern int blf_default_font_render; // dont mess drawing with render threads. #endif /* BLF_API_H */ diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index c0e62b1c0c7..3bfb7c22082 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -74,6 +74,7 @@ static int global_font_dpi= 72; // XXX, should these be made into global_font_'s too? int blf_mono_font= -1; int blf_mono_font_render= -1; +int blf_default_font_render= -1; static FontBLF *BLF_get(int fontid) { diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 7c0e7050a9f..ddff45c5422 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -154,6 +154,7 @@ void constraints_clear_evalob(struct bConstraintOb *cob); void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to); void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime); +void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 04597fd666e..7402d501120 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -104,4 +104,6 @@ int sound_read_sound_buffer(struct bSound* sound, float* buffer, int length, flo int sound_get_channels(struct bSound* sound); +void* sound_get_factory(void* sound); + #endif diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index f7086c81756..08eed6d61ba 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -85,8 +85,6 @@ bAction *add_empty_action(const char name[]) bAction *act; act= alloc_libblock(&G.main->action, ID_AC, name); - act->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore - act->id.us++; return act; } @@ -200,9 +198,6 @@ bAction *copy_action (bAction *src) } } - dst->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore - dst->id.us++; - return dst; } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7be4744a224..a321e718bbb 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2641,7 +2641,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* if inside, then move to surface */ if (dist <= data->dist) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ else if (data->flag & LIMITDIST_USESOFT) { @@ -2654,14 +2654,14 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* if outside, then move to surface */ if (dist >= data->dist) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ else if (data->flag & LIMITDIST_USESOFT) { // FIXME: there's a problem with "jumping" when this kicks in if (dist >= (data->dist - data->soft)) { sfac = (float)( data->soft*(1.0f - expf(-(dist - data->dist)/data->soft)) + data->dist ); - sfac /= dist; + if (dist != 0.0f) sfac /= dist; clamp_surf= 1; } @@ -2670,7 +2670,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * else { if (IS_EQF(dist, data->dist)==0) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } } @@ -4420,6 +4420,34 @@ void get_constraint_target_matrix (struct Scene *scene, bConstraint *con, int n, unit_m4(mat); } } + +/* Get the list of targets required for solving a constraint */ +void get_constraint_targets_for_solving (bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) +{ + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + if (cti && cti->get_constraint_targets) { + bConstraintTarget *ct; + + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, targets); + + /* set matrices + * - calculate if possible, otherwise just initialise as identity matrix + */ + if (cti->get_target_matrix) { + for (ct= targets->first; ct; ct= ct->next) + cti->get_target_matrix(con, cob, ct, ctime); + } + else { + for (ct= targets->first; ct; ct= ct->next) + unit_m4(ct->matrix); + } + } +} /* ---------- Evaluation ----------- */ @@ -4464,27 +4492,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); /* prepare targets for constraint solving */ - if (cti->get_constraint_targets) { - bConstraintTarget *ct; - - /* get targets - * - constraints should use ct->matrix, not directly accessing values - * - ct->matrix members have not yet been calculated here! - */ - cti->get_constraint_targets(con, &targets); - - /* set matrices - * - calculate if possible, otherwise just initialise as identity matrix - */ - if (cti->get_target_matrix) { - for (ct= targets.first; ct; ct= ct->next) - cti->get_target_matrix(con, cob, ct, ctime); - } - else { - for (ct= targets.first; ct; ct= ct->next) - unit_m4(ct->matrix); - } - } + get_constraint_targets_for_solving(con, cob, &targets, ctime); /* Solve the constraint and put result in cob->matrix */ cti->evaluate_constraint(con, cob, &targets); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d6a9d950015..1f45cc56117 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -42,6 +42,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_constraint_types.h" #include "DNA_object_types.h" #include "BLI_blenlib.h" @@ -52,6 +53,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_global.h" #include "BKE_object.h" @@ -1151,25 +1153,50 @@ static float dvar_eval_locDiff (ChannelDriver *driver, DriverVar *dvar) /* check if object or bone */ if (pchan) { /* bone */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) { + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + + /* ... and from that, we get our transform */ + VECCOPY(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + VECCOPY(tmp_loc, pchan->loc); + } + } + else { /* convert to worldspace */ VECCOPY(tmp_loc, pchan->pose_head); mul_m4_v3(ob->obmat, tmp_loc); } - else { - /* local (use transform values directly) */ - VECCOPY(tmp_loc, pchan->loc); - } } else { /* object */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) { - /* worldspace */ - VECCOPY(tmp_loc, ob->obmat[3]); + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + // XXX: this should practically be the same as transform space... + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + + /* ... and from that, we get our transform */ + VECCOPY(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + VECCOPY(tmp_loc, ob->loc); + } } else { - /* local (use transform values directly) */ - VECCOPY(tmp_loc, ob->loc); + /* worldspace */ + VECCOPY(tmp_loc, ob->obmat[3]); } } @@ -1197,7 +1224,7 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) Object *ob= (Object *)dtar_id_ensure_proxy_from(dtar->id); bPoseChannel *pchan; float mat[4][4]; - float eul[3] = {0.0f,0.0f,0.0f}; + float oldEul[3] = {0.0f,0.0f,0.0f}; short useEulers=0, rotOrder=ROT_MODE_EUL; /* check if this target has valid data */ @@ -1210,36 +1237,62 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) /* try to get posechannel */ pchan= get_pose_channel(ob->pose, dtar->pchan_name); - /* check if object or bone, and get transform matrix accordingly */ + /* check if object or bone, and get transform matrix accordingly + * - "useEulers" code is used to prevent the problems associated with non-uniqueness + * of euler decomposition from matrices [#20870] + * - localspace is for [#21384], where parent results are not wanted + * but local-consts is for all the common "corrective-shapes-for-limbs" situations + */ if (pchan) { /* bone */ if (pchan->rotmode > 0) { - VECCOPY(eul, pchan->eul); + VECCOPY(oldEul, pchan->eul); rotOrder= pchan->rotmode; useEulers = 1; } if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - /* specially calculate local matrix, since chan_mat is not valid - * since it stores delta transform of pose_mat so that deforms work - */ - pchan_to_mat4(pchan, mat); + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + } + else { + /* specially calculate local matrix, since chan_mat is not valid + * since it stores delta transform of pose_mat so that deforms work + * so it cannot be used here for "transform" space + */ + pchan_to_mat4(pchan, mat); + } } - else + else { + /* worldspace matrix */ mul_m4_m4m4(mat, pchan->pose_mat, ob->obmat); + } } else { /* object */ if (ob->rotmode > 0) { - VECCOPY(eul, ob->rot); + VECCOPY(oldEul, ob->rot); rotOrder= ob->rotmode; useEulers = 1; } - if (dtar->flag & DTAR_FLAG_LOCALSPACE) - object_to_mat4(ob, mat); - else + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + } + else { + /* transforms to matrix */ + object_to_mat4(ob, mat); + } + } + else { + /* worldspace matrix - just the good-old one */ copy_m4_m4(mat, ob->obmat); + } } /* check which transform */ @@ -1255,9 +1308,21 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) return scale[dtar->transChan - DTAR_TRANSCHAN_SCALEX]; } else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { - /* extract euler rotation (if needed), and choose the right axis */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE)==0 || (useEulers == 0)) - mat4_to_eulO(eul, rotOrder, mat); + /* extract rotation as eulers (if needed) + * - definitely if rotation order isn't eulers already + * - if eulers, then we have 2 options: + * a) decompose transform matrix as required, then try to make eulers from + * there compatible with original values + * b) [NOT USED] directly use the original values (no decomposition) + * - only an option for "transform space", if quality is really bad with a) + */ + float eul[3]; + + mat4_to_eulO(eul, rotOrder, mat); + + if (useEulers) { + compatible_eul(eul, oldEul); + } return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX]; } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 844f25e6d21..dcf81c19479 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -1013,6 +1013,7 @@ FModifier *add_fmodifier (ListBase *modifiers, int type) fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); fcm->type = type; fcm->flag = FMODIFIER_FLAG_EXPANDED; + fcm->influence = 1.0f; BLI_addtail(modifiers, fcm); /* tag modifier as "active" if no other modifiers exist in the stack yet */ @@ -1200,6 +1201,47 @@ short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype /* Evaluation API --------------------------- */ +/* helper function - calculate influence of FModifier */ +static float eval_fmodifier_influence (FModifier *fcm, float evaltime) +{ + float influence; + + /* sanity check */ + if (fcm == NULL) + return 0.0f; + + /* should we use influence stored in modifier or not + * NOTE: this is really just a hack so that we don't need to version patch old files ;) + */ + if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) + influence = fcm->influence; + else + influence = 1.0f; + + /* restricted range or full range? */ + if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { + if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) { + /* out of range */ + return 0.0f; + } + else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) { + /* blend in range */ + float a = fcm->sfra; + float b = fcm->sfra + fcm->blendin; + return influence * (evaltime - a) / (b - a); + } + else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) { + /* blend out range */ + float a = fcm->efra; + float b = fcm->efra - fcm->blendout; + return influence * (evaltime - a) / (b - a); + } + } + + /* just return the influence of the modifier */ + return influence; +} + /* 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 @@ -1230,11 +1272,24 @@ float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, for (fcm= 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) - evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + if (fmi == NULL) + continue; + + /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results) + * hence we shouldn't bother seeing what it would do given the chance + */ + if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || + ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) ) + { + /* only evaluate if there's a callback for this */ + if (fmi->evaluate_modifier_time) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) { + float influence = eval_fmodifier_influence(fcm, evaltime); + float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + + evaltime = interpf(nval, evaltime, influence); + } + } } } @@ -1257,11 +1312,22 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, 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); + if (fmi == NULL) + continue; + + /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */ + if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || + ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) ) + { + if (fmi->evaluate_modifier) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) { + float influence = eval_fmodifier_influence(fcm, evaltime); + float nval = *cvalue; + + fmi->evaluate_modifier(fcu, fcm, &nval, evaltime); + *cvalue = interpf(nval, *cvalue, influence); + } + } } } } diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index fbb5a77fa04..688fdd8ff49 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -40,8 +40,11 @@ #include "BLI_dynlib.h" #include "BLI_math.h" /* windows needs for M_PI */ +#include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLF_api.h" + #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_anim_types.h" @@ -2805,6 +2808,130 @@ static struct ImBuf * do_solid_color( } /* ********************************************************************** + TITLE CARD + ********************************************************************** */ + +static void init_title_card(Sequence *seq) +{ + TitleCardVars *tv; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct TitleCardVars), "titlecard"); + + tv = (TitleCardVars *)seq->effectdata; + + BLI_strncpy(tv->titlestr, "Title goes here", sizeof(tv->titlestr)); + tv->fgcol[0] = tv->fgcol[1] = tv->fgcol[2] = 1.0f; /* white */ +} + +static int num_inputs_titlecard(void) +{ + return 0; +} + +static void free_title_card(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = NULL; +} + +static void copy_title_card(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static int early_out_titlecard(struct Sequence *UNUSED(seq), + float UNUSED(facf0), float UNUSED(facf1)) +{ + return -1; +} + +static struct ImBuf * do_title_card( + SeqRenderData context, Sequence *seq, float cfra, + float facf0, float facf1, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3) +{ + TitleCardVars *tv = (TitleCardVars *)seq->effectdata; + + SolidColorVars cv = {{0}}; + struct ImBuf *out; + + int titleFontId = blf_default_font_render; // XXX: bad design! + + int width = context.rectx; + int height = context.recty; + float w, h; + int x, y; + + /* use fake solid-color vars to get backdrop (and an out buffer at the same time) */ + VECCOPY(cv.col, tv->bgcol); + seq->effectdata = &cv; + + out = do_solid_color(context, seq, cfra, + facf0, facf1, + ibuf1, ibuf2, ibuf3); + + seq->effectdata = tv; + + /* draw text */ + /* FIXME: imbuf out->rect is unsigned int NOT unsigned char, but without passing this pointer + * this drawing code doesn't work. This cast really masks some potential bugs though... + */ + BLF_buffer(titleFontId, out->rect_float, (unsigned char *)out->rect, width, height, 4); + + if (tv->titlestr[0]) { + /* automatic scale - these formulae have been derived experimentally: + * - base size is based on 40pt at 960 width + * - each 26 characters, size jumps down one step, + * but this decrease needs to be exponential to fit everything + */ + float lfac = strlen(tv->titlestr) / 26.0f; + float size = (width * 0.06f) * (1.0f - 0.1f*lfac*lfac); + + BLF_size(titleFontId, size, 72); + BLF_buffer_col(titleFontId, tv->fgcol[0], tv->fgcol[1], tv->fgcol[2], 1.0); + + BLF_width_and_height(titleFontId, tv->titlestr, &w, &h); + x = width/2.0f - w/2.0f; + if (tv->subtitle[0]) + y = height/2.0f + h; + else + y = height/2.0f; + + BLF_position(titleFontId, x, y, 0.0); + BLF_draw_buffer(titleFontId, tv->titlestr); + } + + if (tv->subtitle[0]) { + /* automatic scale - these formulae have been derived experimentally (as above): + * - base size is based on 20pt at 960 width + * - size steps aren't quite as refined here. Need a slower-growing curve! + */ + float lfac = strlen(tv->subtitle) / 36.0f; + float size = (width * 0.03f) * (1.0f - 0.1f*lfac*lfac*log(lfac)); + + BLF_size(titleFontId, size, 72); + BLF_buffer_col(titleFontId, tv->fgcol[0], tv->fgcol[1], tv->fgcol[2], 1.0); + + BLF_width_and_height(titleFontId, tv->subtitle, &w, &h); + x = width/2.0f - w/2.0f; + if (tv->titlestr[0]) + y = height/2.0f - h; + else + y = height/2.0f; + + BLF_position(titleFontId, x, y, 0.0); + BLF_draw_buffer(titleFontId, tv->subtitle); + } + + /* cleanup the buffer. */ + BLF_buffer(UIFONT_DEFAULT, NULL, NULL, 0, 0, 0); + + return out; +} + +/* ********************************************************************** MULTICAM ********************************************************************** */ @@ -3343,6 +3470,14 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.early_out = early_out_adjustment; rval.execute = do_adjustment; break; + case SEQ_TITLECARD: + rval.init = init_title_card; + rval.num_inputs = num_inputs_titlecard; + rval.early_out = early_out_titlecard; + rval.free = free_title_card; + rval.copy = copy_title_card; + rval.execute = do_title_card; + break; } return rval; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b82ac69fc9e..550b81e8a0f 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -895,6 +895,7 @@ static const char *give_seqname_by_type(int type) case SEQ_MULTICAM: return "Multicam"; case SEQ_ADJUSTMENT: return "Adjustment"; case SEQ_SPEED: return "Speed"; + case SEQ_TITLECARD: return "Title Card"; default: return NULL; } @@ -3020,7 +3021,7 @@ Sequence *seq_foreground_frame_get(Scene *scene, int frame) if(seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) continue; /* only use elements you can see - not */ - if (ELEM5(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_COLOR)) { + if (ELEM6(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_COLOR, SEQ_TITLECARD)) { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index e0e456a371e..f42492ef713 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -502,3 +502,8 @@ int sound_get_channels(struct bSound* sound) return info.specs.channels; } + +void* sound_get_factory(void* sound) +{ + return ((struct bSound*) sound)->playback_handle; +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 222c4bcf6fc..b8a72616593 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -11663,8 +11663,42 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + + { + /* convert fcurve actuator to action actuator */ + Object *ob; + bActuator *act; + bIpoActuator *ia; + bActionActuator *aa; + + for (ob= main->object.first; ob; ob= ob->id.next) { + for (act= ob->actuators.first; act; act= act->next) { + if (act->type == ACT_IPO) { + // Create the new actuator + ia= act->data; + aa= MEM_callocN(sizeof(bActionActuator), "fcurve -> action actuator do_version"); + + // Copy values + aa->type = ia->type; + aa->flag = ia->flag; + aa->sta = ia->sta; + aa->end = ia->end; + strcpy(aa->name, ia->name); + strcpy(aa->frameProp, ia->frameProp); + aa->act = ob->adt->action; + + // Get rid of the old actuator + MEM_freeN(ia); + + // Assign the new actuator + act->data = aa; + act->type= act->otype= ACT_ACTION; + + } + } + } + } } - /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 240e8d00ab8..fb5c96cd854 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1892,6 +1892,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase) case SEQ_TRANSFORM: writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); break; + case SEQ_TITLECARD: + writestruct(wd, DATA, "TitleCardVars", 1, seq->effectdata); + break; } } diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp new file mode 100644 index 00000000000..f0491af3a49 --- /dev/null +++ b/source/blender/collada/AnimationExporter.cpp @@ -0,0 +1,854 @@ +/* + * $Id: DocumentExporter.cpp 36898 2011-05-25 17:14:31Z phabtar $ + * + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GeometryExporter.h" +#include "AnimationExporter.h" + +template<class Functor> +void forEachObjectInScene(Scene *sce, Functor &f) +{ + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + f(ob); + + base= base->next; + } +} + +void AnimationExporter::exportAnimations(Scene *sce) + { + if(hasAnimations(sce)) { + this->scene = sce; + + openLibrary(); + + forEachObjectInScene(sce, *this); + + closeLibrary(); + } + } + + // called for each exported object + void AnimationExporter::operator() (Object *ob) + { + if (!ob->adt || !ob->adt->action) return; //this is already checked in hasAnimations() + FCurve *fcu = (FCurve*)ob->adt->action->curves.first; + char * transformName = extract_transform_name( fcu->rna_path ); + + + //if (ob->type == OB_ARMATURE) { + // if (!ob->data) return; + // bArmature *arm = (bArmature*)ob->data; + // while(fcu) + // { + // transformName = extract_transform_name( fcu->rna_path ); + // // std::string ob_name = getObjectBoneName( ob , fcu); + // // for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) + // // write_bone_animation(ob, bone); + // dae_animation(ob, fcu, ob_name, transformName); + // fcu = fcu->next; + // } + //} + //else { + while (fcu) { + transformName = extract_transform_name( fcu->rna_path ); + + if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) || + (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)|| + (!strcmp(transformName, "rotation_quaternion"))) + dae_animation(ob ,fcu, transformName ); + + fcu = fcu->next; + } + //} + } + + float * AnimationExporter::get_eul_source_for_quat(Object *ob ) + { + FCurve *fcu = (FCurve*)ob->adt->action->curves.first; + const int keys = fcu->totvert; + float *quat = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values"); + float *eul = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values"); + float temp_quat[4]; + float temp_eul[3]; + while(fcu) + { + char * transformName = extract_transform_name( fcu->rna_path ); + + if( !strcmp(transformName, "rotation_quaternion") ) + { + for ( int i = 0 ; i < fcu->totvert ; i++) + { + *(quat + ( i * 4 ) + fcu->array_index) = fcu->bezt[i].vec[1][1]; + } + } + fcu = fcu->next; + } + + for ( int i = 0 ; i < fcu->totvert ; i++) + { + for ( int j = 0;j<4;j++) + temp_quat[j] = quat[(i*4)+j]; + + quat_to_eul(temp_eul,temp_quat); + + for (int k = 0;k<3;k++) + eul[i*3 + k] = temp_eul[k]; + + } + + return eul; + + } + std::string AnimationExporter::getObjectBoneName( Object* ob,const FCurve* fcu ) + { + //hard-way to derive the bone name from rna_path. Must find more compact method + std::string rna_path = std::string(fcu->rna_path); + + char* boneName = strtok((char *)rna_path.c_str(), "\""); + boneName = strtok(NULL,"\""); + + if( boneName != NULL ) + return id_name(ob) + "_" + std::string(boneName); + else + return id_name(ob); + } + + void AnimationExporter::dae_animation(Object* ob, FCurve *fcu/*, std::string ob_name*/ , char* transformName ) + { + + const char *axis_name = NULL; + char anim_id[200]; + + bool has_tangents = false; + bool quatRotation = false; + + if ( !strcmp(transformName, "rotation_quaternion") ) + { + quatRotation = true; + /*const char *axis_names[] = {"", "X", "Y", "Z"}; + if (fcu->array_index < 4) + axis_name = axis_names[fcu->array_index];*/ + } + + else + { + const char *axis_names[] = {"X", "Y", "Z"}; + if (fcu->array_index < 3) + axis_name = axis_names[fcu->array_index]; + } + std::string ob_name = std::string("null"); + if (ob->type == OB_ARMATURE) + { + ob_name = getObjectBoneName( ob , fcu); + BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char*)translate_id(ob_name).c_str(), + transformName, axis_name); + } + else + { + ob_name = id_name(ob); + BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), + fcu->rna_path, axis_name); + } + + // check rna_path is one of: rotation, scale, location + + openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); + + // create input source + std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name); + + // create output source + std::string output_id ; + + /*if(quatRotation) + { + float * eul = get_eul_source_for_quat(ob); + float * eul_axis = + for ( int i = 0 ; i< fcu->totvert ; i++) + eul_axis[i] = eul[i*3 + fcu->array_index]; + output_id= create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis , fcu->totvert, quatRotation, anim_id, axis_name); + } + else*/ + + output_id= create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name); + + // create interpolations source + std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents); + + // handle tangents (if required) + std::string intangent_id; + std::string outtangent_id; + + if (has_tangents) { + // create in_tangent source + intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name); + + // create out_tangent source + outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name); + } + + + std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; + COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); + std::string empty; + sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); + sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); + + // this input is required + sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + + if (has_tangents) { + sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id)); + sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id)); + } + + addSampler(sampler); + + std::string target = translate_id(ob_name) + + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true); + addChannel(COLLADABU::URI(empty, sampler_id), target); + + closeAnimation(); + } + + void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone) + { + if (!ob_arm->adt) + return; + + //write bone animations for 3 transform types + //i=0 --> rotations + //i=1 --> scale + //i=2 --> location + for (int i = 0; i < 3; i++) + sample_and_write_bone_animation(ob_arm, bone, i); + + for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) + write_bone_animation(ob_arm, child); + } + + void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) + { + bArmature *arm = (bArmature*)ob_arm->data; + int flag = arm->flag; + std::vector<float> fra; + char prefix[256]; + + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name); + + bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); + if (!pchan) + return; + //Fill frame array with key frame values framed at @param:transform_type + switch (transform_type) { + case 0: + find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); + break; + case 1: + find_frames(ob_arm, fra, prefix, "scale"); + break; + case 2: + find_frames(ob_arm, fra, prefix, "location"); + break; + default: + return; + } + + // exit rest position + if (flag & ARM_RESTPOS) { + arm->flag &= ~ARM_RESTPOS; + where_is_pose(scene, ob_arm); + } + //v array will hold all values which will be exported. + if (fra.size()) { + float *values = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); + sample_animation(values, fra, transform_type, bone, ob_arm, pchan); + + if (transform_type == 0) { + // write x, y, z curves separately if it is rotation + float *axisValues = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames"); + + for (int i = 0; i < 3; i++) { + for (unsigned int j = 0; j < fra.size(); j++) + axisValues[j] = values[j * 3 + i]; + + dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name); + } + MEM_freeN(axisValues); + } + else { + // write xyz at once if it is location or scale + dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name); + } + + MEM_freeN(values); + } + + // restore restpos + if (flag & ARM_RESTPOS) + arm->flag = flag; + where_is_pose(scene, ob_arm); + } + + void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan) + { + bPoseChannel *parchan = NULL; + bPose *pose = ob_arm->pose; + + pchan = get_pose_channel(pose, bone->name); + + if (!pchan) + return; + + parchan = pchan->parent; + + enable_fcurves(ob_arm->adt->action, bone->name); + + std::vector<float>::iterator it; + for (it = frames.begin(); it != frames.end(); it++) { + float mat[4][4], ipar[4][4]; + + float ctime = bsystem_time(scene, ob_arm, *it, 0.0f); + + BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM); + where_is_pose_bone(scene, ob_arm, pchan, ctime, 1); + + // compute bone local mat + if (bone->parent) { + invert_m4_m4(ipar, parchan->pose_mat); + mul_m4_m4m4(mat, pchan->pose_mat, ipar); + } + else + copy_m4_m4(mat, pchan->pose_mat); + + switch (type) { + case 0: + mat4_to_eul(v, mat); + break; + case 1: + mat4_to_size(v, mat); + break; + case 2: + copy_v3_v3(v, mat[3]); + break; + } + + v += 3; + } + + enable_fcurves(ob_arm->adt->action, NULL); + } + + // dae_bone_animation -> add_bone_animation + // (blend this into dae_bone_animation) + void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name) + { + const char *axis_names[] = {"X", "Y", "Z"}; + const char *axis_name = NULL; + char anim_id[200]; + bool is_rot = tm_type == 0; + + if (!fra.size()) + return; + + char rna_path[200]; + BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(), + tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location")); + + if (axis > -1) + axis_name = axis_names[axis]; + + std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false); + + BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), + (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str()); + + openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); + + // create input source + std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name); + + // create output source + std::string output_id; + if (axis == -1) + output_id = create_xyz_source(values, fra.size(), anim_id); + else + output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name); + + // create interpolations source + std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name); + + std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; + COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); + std::string empty; + sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); + sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); + + // TODO create in/out tangents source + + // this input is required + sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + + addSampler(sampler); + + std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; + addChannel(COLLADABU::URI(empty, sampler_id), target); + + closeAnimation(); + } + + float AnimationExporter::convert_time(float frame) + { + return FRA2TIME(frame); + } + + float AnimationExporter::convert_angle(float angle) + { + return COLLADABU::Math::Utils::radToDegF(angle); + } + + std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic) + { + switch(semantic) { + case COLLADASW::InputSemantic::INPUT: + return INPUT_SOURCE_ID_SUFFIX; + case COLLADASW::InputSemantic::OUTPUT: + return OUTPUT_SOURCE_ID_SUFFIX; + case COLLADASW::InputSemantic::INTERPOLATION: + return INTERPOLATION_SOURCE_ID_SUFFIX; + case COLLADASW::InputSemantic::IN_TANGENT: + return INTANGENT_SOURCE_ID_SUFFIX; + case COLLADASW::InputSemantic::OUT_TANGENT: + return OUTTANGENT_SOURCE_ID_SUFFIX; + default: + break; + } + return ""; + } + + void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, + COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis) + { + switch(semantic) { + case COLLADASW::InputSemantic::INPUT: + param.push_back("TIME"); + break; + case COLLADASW::InputSemantic::OUTPUT: + if (is_rot) { + param.push_back("ANGLE"); + } + else { + if (axis) { + param.push_back(axis); + } + else { //assumes if axis isn't specified all axises are added + param.push_back("X"); + param.push_back("Y"); + param.push_back("Z"); + } + } + break; + case COLLADASW::InputSemantic::IN_TANGENT: + case COLLADASW::InputSemantic::OUT_TANGENT: + param.push_back("X"); + param.push_back("Y"); + break; + default: + break; + } + } + + void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length) + { + switch (semantic) { + case COLLADASW::InputSemantic::INPUT: + *length = 1; + values[0] = convert_time(bezt->vec[1][0]); + break; + case COLLADASW::InputSemantic::OUTPUT: + *length = 1; + if (rotation) { + values[0] = (bezt->vec[1][1]) * 180.0f/M_PI; + } + else { + values[0] = bezt->vec[1][1]; + } + break; + + case COLLADASW::InputSemantic::IN_TANGENT: + *length = 2; + values[0] = convert_time(bezt->vec[0][0]); + if (bezt->ipo != BEZT_IPO_BEZ) { + // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data + values[0] = 0; + values[1] = 0; + } + else if (rotation) { + values[1] = (bezt->vec[0][1]) * 180.0f/M_PI; + } else { + values[1] = bezt->vec[0][1]; + } + break; + + case COLLADASW::InputSemantic::OUT_TANGENT: + *length = 2; + values[0] = convert_time(bezt->vec[2][0]); + if (bezt->ipo != BEZT_IPO_BEZ) { + // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data + values[0] = 0; + values[1] = 0; + } + else if (rotation) { + values[1] = (bezt->vec[0][1]) * 180.0f/M_PI; + } else { + values[1] = bezt->vec[2][1]; + } + break; + break; + default: + *length = 0; + break; + } + } + + std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) + { + std::string source_id = anim_id + get_semantic_suffix(semantic); + + //bool is_rotation = !strcmp(fcu->rna_path, "rotation"); + bool is_rotation = false; + + if (strstr(fcu->rna_path, "rotation")) is_rotation = true; + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(fcu->totvert); + + switch (semantic) { + case COLLADASW::InputSemantic::INPUT: + case COLLADASW::InputSemantic::OUTPUT: + source.setAccessorStride(1); + break; + case COLLADASW::InputSemantic::IN_TANGENT: + case COLLADASW::InputSemantic::OUT_TANGENT: + source.setAccessorStride(2); + break; + } + + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, is_rotation, axis_name); + + source.prepareToAppendValues(); + + for (unsigned int i = 0; i < fcu->totvert; i++) { + float values[3]; // be careful! + int length = 0; + get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length); + for (int j = 0; j < length; j++) + source.appendValues(values[j]); + } + + source.finish(); + + return source_id; + } + + //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified ) + std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name) + { + std::string source_id = anim_id + get_semantic_suffix(semantic); + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(tot); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, is_rot, axis_name); + + source.prepareToAppendValues(); + + for (int i = 0; i < tot; i++) { + float val = v[i]; + ////if (semantic == COLLADASW::InputSemantic::INPUT) + // val = convert_time(val); + //else + if (is_rot) + val *= 180.0f / M_PI; + source.appendValues(val); + } + + source.finish(); + + return source_id; + } +// only used for sources with INPUT semantic + std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name) + { + std::string source_id = anim_id + get_semantic_suffix(semantic); + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(fra.size()); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, is_rot, axis_name); + + source.prepareToAppendValues(); + + std::vector<float>::iterator it; + for (it = fra.begin(); it != fra.end(); it++) { + float val = *it; + //if (semantic == COLLADASW::InputSemantic::INPUT) + val = convert_time(val); + /*else if (is_rot) + val = convert_angle(val);*/ + source.appendValues(val); + } + + source.finish(); + + return source_id; + } + + // only used for sources with OUTPUT semantic ( locations and scale) + std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id) + { + COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; + std::string source_id = anim_id + get_semantic_suffix(semantic); + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(tot); + source.setAccessorStride(3); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, false, NULL); + + source.prepareToAppendValues(); + + for (int i = 0; i < tot; i++) { + source.appendValues(*v, *(v + 1), *(v + 2)); + v += 3; + } + + source.finish(); + + return source_id; + } + + std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents) + { + std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); + + COLLADASW::NameSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(fcu->totvert); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("INTERPOLATION"); + + source.prepareToAppendValues(); + + *has_tangents = false; + + for (unsigned int i = 0; i < fcu->totvert; i++) { + if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) { + source.appendValues(BEZIER_NAME); + *has_tangents = true; + } else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) { + source.appendValues(STEP_NAME); + } else { // BEZT_IPO_LIN + source.appendValues(LINEAR_NAME); + } + } + // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS + + source.finish(); + + return source_id; + } + + std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name) + { + std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); + + COLLADASW::NameSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(tot); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("INTERPOLATION"); + + source.prepareToAppendValues(); + + for (int i = 0; i < tot; i++) { + source.appendValues(LINEAR_NAME); + } + + source.finish(); + + return source_id; + } + + // for rotation, axis name is always appended and the value of append_axis is ignored + std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) + { + std::string tm_name; + bool is_rotation =false; + // when given rna_path, determine tm_type from it + if (rna_path) { + char *name = extract_transform_name(rna_path); + + if (!strcmp(name, "rotation_euler")) + tm_type = 0; + else if (!strcmp(name, "rotation_quaternion")) + tm_type = 1; + else if (!strcmp(name, "scale")) + tm_type = 2; + else if (!strcmp(name, "location")) + tm_type = 3; + else + tm_type = -1; + } + + switch (tm_type) { + case 0: + case 1: + tm_name = "rotation"; + is_rotation = true; + break; + case 2: + tm_name = "scale"; + break; + case 3: + tm_name = "location"; + break; + default: + tm_name = ""; + break; + } + + if (tm_name.size()) { + if (is_rotation) + return tm_name + std::string(axis_name); + else + return tm_name; + } + + return std::string(""); + } + + char* AnimationExporter::extract_transform_name(char *rna_path) + { + char *dot = strrchr(rna_path, '.'); + return dot ? (dot + 1) : rna_path; + } + + void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name) + { + FCurve *fcu= (FCurve*)ob->adt->action->curves.first; + + for (; fcu; fcu = fcu->next) { + if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix))) + continue; + + char *name = extract_transform_name(fcu->rna_path); + if (!strcmp(name, tm_name)) { + for (unsigned int i = 0; i < fcu->totvert; i++) { + float f = fcu->bezt[i].vec[1][0]; // + if (std::find(fra.begin(), fra.end(), f) == fra.end()) + fra.push_back(f); + } + } + } + + // keep the keys in ascending order + std::sort(fra.begin(), fra.end()); + } + + void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode) + { + if (rotmode > 0) + find_frames(ob, fra, prefix, "rotation_euler"); + else if (rotmode == ROT_MODE_QUAT) + find_frames(ob, fra, prefix, "rotation_quaternion"); + /*else if (rotmode == ROT_MODE_AXISANGLE) + ;*/ + } + + // enable fcurves driving a specific bone, disable all the rest + // if bone_name = NULL enable all fcurves + void AnimationExporter::enable_fcurves(bAction *act, char *bone_name) + { + FCurve *fcu; + char prefix[200]; + + if (bone_name) + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); + + for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) { + if (bone_name) { + if (!strncmp(fcu->rna_path, prefix, strlen(prefix))) + fcu->flag &= ~FCURVE_DISABLED; + else + fcu->flag |= FCURVE_DISABLED; + } + else { + fcu->flag &= ~FCURVE_DISABLED; + } + } + } + + bool AnimationExporter::hasAnimations(Scene *sce) + { + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + FCurve *fcu = 0; + if(ob->adt && ob->adt->action) + fcu = (FCurve*)ob->adt->action->curves.first; + + //The Scene has animations if object type is armature or object has f-curve + if ((ob->type == OB_ARMATURE && ob->data) || fcu) { + return true; + } + base= base->next; + } + return false; + } diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h new file mode 100644 index 00000000000..e05fac4eed7 --- /dev/null +++ b/source/blender/collada/AnimationExporter.h @@ -0,0 +1,144 @@ +/* + * $Id: DocumentExporter.cpp 36898 2011-05-25 17:14:31Z phabtar $ + * + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +extern "C" +{ +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" +#include "DNA_curve_types.h" +#include "DNA_armature_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_fcurve.h" +#include "BKE_animsys.h" +#ifdef NAN_BUILDINFO +extern char build_rev[]; +#endif +} + +#include "MEM_guardedalloc.h" + +#include "BKE_action.h" // pose functions +#include "BKE_armature.h" +#include "BKE_object.h" + +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_listbase.h" + +#include "RNA_access.h" + +#include "COLLADASWSource.h" +#include "COLLADASWInstanceGeometry.h" +#include "COLLADASWInputList.h" +#include "COLLADASWPrimitves.h" +#include "COLLADASWVertices.h" +#include "COLLADASWLibraryAnimations.h" +#include "COLLADASWParamTemplate.h" +#include "COLLADASWParamBase.h" +#include "COLLADASWSampler.h" +#include "COLLADASWConstants.h" +#include "COLLADASWBaseInputElement.h" + +#include "collada_internal.h" + +#include <vector> +#include <algorithm> // std::find + +class AnimationExporter: COLLADASW::LibraryAnimations +{ +private: + Scene *scene; + COLLADASW::StreamWriter *sw; + +public: + + AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; } + + + void exportAnimations(Scene *sce); + + // called for each exported object + void operator() (Object *ob); + +protected: + + void dae_animation(Object* ob, FCurve *fcu, char* transformName); + + void write_bone_animation(Object *ob_arm, Bone *bone); + + void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type); + + void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pChan); + + // dae_bone_animation -> add_bone_animation + // (blend this into dae_bone_animation) + void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name); + + float convert_time(float frame); + + float convert_angle(float angle); + + std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic); + + void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, + COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis); + + void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length); + + float * get_eul_source_for_quat(Object *ob ); + + std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name); + + std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name); + + std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name); + + std::string create_xyz_source(float *v, int tot, const std::string& anim_id); + + std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents); + + std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name); + // for rotation, axis name is always appended and the value of append_axis is ignored + std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); + + void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name); + + void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode); + + // enable fcurves driving a specific bone, disable all the rest + // if bone_name = NULL enable all fcurves + void enable_fcurves(bAction *act, char *bone_name); + + bool hasAnimations(Scene *sce); + + char* extract_transform_name(char *rna_path); + + std::string getObjectBoneName ( Object *ob,const FCurve * fcu); +};
\ No newline at end of file diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 336f127b11f..69beac653d2 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -89,12 +89,15 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) { COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues(); COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues(); - // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); - // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); + + if( curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER ) { + COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); + COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); + } float fps = (float)FPS; size_t dim = curve->getOutDimension(); unsigned int i; - + std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()]; switch (dim) { @@ -108,28 +111,42 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); // fcu->rna_path = BLI_strdupn(path, strlen(path)); fcu->array_index = 0; - //fcu->totvert = curve->getKeyCount(); + fcu->totvert = curve->getKeyCount(); // create beztriple for each key for (unsigned int j = 0; j < curve->getKeyCount(); j++) { BezTriple bez; memset(&bez, 0, sizeof(BezTriple)); - // intangent - // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps; - // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1); - + // input, output bez.vec[1][0] = bc_get_float_value(input, j) * fps; bez.vec[1][1] = bc_get_float_value(output, j * dim + i); - // outtangent - // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps; - // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1); - bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + if( curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER ) + { + COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); + COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); + + // intangent + bez.vec[0][0] = bc_get_float_value(intan, (j * 2 * dim ) + (2 * i)) * fps; + bez.vec[0][1] = bc_get_float_value(intan, (j * 2 * dim )+ (2 * i) + 1); + + // outtangent + bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim ) + (2 * i)) * fps; + bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim )+ (2 * i) + 1); + bez.ipo = BEZT_IPO_BEZ; + //bez.h1 = bez.h2 = HD_AUTO; + } + else + { + bez.h1 = bez.h2 = HD_AUTO; + bez.ipo = BEZT_IPO_LIN; + } + // bez.ipo = U.ipo_new; /* use default interpolation mode here... */ bez.f1 = bez.f2 = bez.f3 = SELECT; - bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); } @@ -147,11 +164,15 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) unused_curves.push_back(*it); } + void AnimationImporter::fcurve_deg_to_rad(FCurve *cu) { for (unsigned int i = 0; i < cu->totvert; i++) { // TODO convert handles too cu->bezt[i].vec[1][1] *= M_PI / 180.0f; + cu->bezt[i].vec[0][1] *= M_PI / 180.0f; + cu->bezt[i].vec[2][1] *= M_PI / 180.0f; + cu->bezt[i].vec[1][0]; } } @@ -277,10 +298,11 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation* anim) bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* animlist) { const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId(); - + animlist_map[animlist_id] = animlist; - + #if 0 + // should not happen if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) { return true; @@ -291,17 +313,18 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* ani // what does this AnimationList animate? Animation& animated = uid_animated_map[animlist_id]; Object *ob = animated.ob; - + char rna_path[100]; char joint_path[100]; bool is_joint = false; // if ob is NULL, it should be a JOINT if (!ob) { + ob = armature_importer->get_armature_for_joint(animated.node); if (!ob) { - fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node)); +// fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node)); return true; } @@ -309,7 +332,7 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* ani is_joint = true; } - + printf("object for animlist: %s found\n", animlist->getUniqueId().toAscii().c_str()); const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); switch (animated.tm->getTransformationType()) { @@ -512,66 +535,320 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) } #endif -// prerequisites: -// animlist_map - map animlist id -> animlist -// curve_map - map anim id -> curve(s) -Object *AnimationImporter::translate_animation(COLLADAFW::Node *node, - std::map<COLLADAFW::UniqueId, Object*>& object_map, - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, - COLLADAFW::Transformation::TransformationType tm_type, - Object *par_job) + +//sets the rna_path and array index to curve +void AnimationImporter::modify_fcurve(std::vector<FCurve*>* curves , char* rna_path , int array_index ) +{ + std::vector<FCurve*>::iterator it; + int i; + for (it = curves->begin(), i = 0; it != curves->end(); it++, i++) { + FCurve *fcu = *it; + fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); + + if (array_index == -1) fcu->array_index = i; + else fcu->array_index = array_index; + + unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); + } +} + +void AnimationImporter::find_frames( std::vector<float>* frames , std::vector<FCurve*>* curves) { - bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + std::vector<FCurve*>::iterator iter; + for (iter = curves->begin(); iter != curves->end(); iter++) { + FCurve *fcu = *iter; + + for (unsigned int k = 0; k < fcu->totvert; k++) { + //get frame value from bezTriple + float fra = fcu->bezt[k].vec[1][0]; + //if frame already not added add frame to frames + if (std::find(frames->begin(), frames->end(), fra) == frames->end()) + frames->push_back(fra); + + } + } +} + +//creates the rna_paths and array indices of fcurves from animations using transformation and bound animation class of each animation. +void AnimationImporter:: Assign_transform_animations(std::vector<float>* frames, + COLLADAFW::Transformation * transform , + const COLLADAFW::AnimationList::AnimationBinding * binding, + std::vector<FCurve*>* curves, bool is_joint, char * joint_path) +{ + COLLADAFW::Transformation::TransformationType tm_type = transform->getTransformationType(); bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; - bool is_joint = node->getType() == COLLADAFW::Node::JOINT; + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + + //to check if the no of curves are valid + bool xyz = ((tm_type == COLLADAFW::Transformation::TRANSLATE ||tm_type == COLLADAFW::Transformation::SCALE) && binding->animationClass == COLLADAFW::AnimationList::POSITION_XYZ); + + + if (!((!xyz && curves->size() == 1) || (xyz && curves->size() == 3) || is_matrix)) { + fprintf(stderr, "expected %d curves, got %d\n", xyz ? 3 : 1, (int)curves->size()); + return; + } + + //find key frames of the animation and accumulates them to frames of the transformation. + find_frames (frames , curves ); + + char rna_path[100]; + //char joint_path[100]; + + + switch (tm_type) { + case COLLADAFW::Transformation::TRANSLATE: + case COLLADAFW::Transformation::SCALE: + { + bool loc = tm_type == COLLADAFW::Transformation::TRANSLATE; + if (is_joint) + BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale"); + else + BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path)); + + switch (binding->animationClass) { + case COLLADAFW::AnimationList::POSITION_X: + modify_fcurve(curves, rna_path, 0 ); + break; + case COLLADAFW::AnimationList::POSITION_Y: + modify_fcurve(curves, rna_path, 1 ); + break; + case COLLADAFW::AnimationList::POSITION_Z: + modify_fcurve(curves, rna_path, 2 ); + break; + case COLLADAFW::AnimationList::POSITION_XYZ: + modify_fcurve(curves, rna_path, -1 ); + break; + default: + fprintf(stderr, "AnimationClass %d is not supported for %s.\n", + binding->animationClass, loc ? "TRANSLATE" : "SCALE"); + } + break; + } + + + case COLLADAFW::Transformation::ROTATE: + { + if (is_joint) + BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path); + else + BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path)); + std::vector<FCurve*>::iterator iter; + for (iter = curves->begin(); iter != curves->end(); iter++) { + FCurve* fcu = *iter; + + //if transform is rotation the fcurves values must be turned in to radian. + if (is_rotation) + fcurve_deg_to_rad(fcu); + } + COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)transform; + COLLADABU::Math::Vector3& axis = rot->getRotationAxis(); + + switch (binding->animationClass) { + case COLLADAFW::AnimationList::ANGLE: + if (COLLADABU::Math::Vector3::UNIT_X == axis) { + modify_fcurve(curves, rna_path, 0 ); + } + else if (COLLADABU::Math::Vector3::UNIT_Y == axis) { + modify_fcurve(curves, rna_path, 1 ); + } + else if (COLLADABU::Math::Vector3::UNIT_Z == axis) { + modify_fcurve(curves, rna_path, 2 ); + } + break; + case COLLADAFW::AnimationList::AXISANGLE: + // TODO convert axis-angle to quat? or XYZ? + default: + fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n", + binding->animationClass); + } + break; + } + + case COLLADAFW::Transformation::MATRIX: + case COLLADAFW::Transformation::SKEW: + case COLLADAFW::Transformation::LOOKAT: + fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n"); + break; + } + +} +void AnimationImporter::translate_Animations_NEW ( COLLADAFW::Node * node , + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, + std::map<COLLADAFW::UniqueId, Object*>& object_map ) +{ + bool is_joint = node->getType() == COLLADAFW::Node::JOINT; + COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; - Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; + Object *ob = is_joint ? armature_importer->get_armature_for_joint(root) : object_map[node->getUniqueId()]; + const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; + + if ( ! is_object_animated(node) ) return ; + + char joint_path[200]; + if ( is_joint ) + armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); + + bAction * act; + bActionGroup *grp = NULL; + + if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1); + else act = ob->adt->action; + //Get the list of animation curves of the object + + ListBase *AnimCurves = &(act->curves); + if (!ob) { fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str()); - return NULL; + return; } - // frames at which to sample - std::vector<float> frames; + + /*float irest_dae[4][4]; + float rest[4][4], irest[4][4]; + + if (is_joint) { + get_joint_rest_mat(irest_dae, root, node); + invert_m4(irest_dae); + + Bone *bone = get_named_bone((bArmature*)ob->data, bone_name); + if (!bone) { + fprintf(stderr, "cannot find bone \"%s\"\n", bone_name); + return; + } + + unit_m4(rest); + copy_m4_m4(rest, bone->arm_mat); + invert_m4_m4(irest, rest); + }*/ + + const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations(); + + //for each transformation in node + for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) { + COLLADAFW::Transformation *transform = nodeTransforms[i]; + COLLADAFW::Transformation::TransformationType tm_type = transform->getTransformationType(); + + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; + + const COLLADAFW::UniqueId& listid = transform->getAnimationList(); + + //might not be needed + std::vector<float> frames; + + //check if transformation has animations + if (animlist_map.find(listid) == animlist_map.end()) continue ; + else + { + //transformation has animations + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + //all the curves belonging to the current binding + std::vector<FCurve*> animcurves; + for (unsigned int j = 0; j < bindings.getCount(); j++) { + animcurves = curve_map[bindings[j].animation]; + //calculate rnapaths and array index of fcurves according to transformation and animation class + Assign_transform_animations(&frames,transform, &bindings[j], &animcurves, is_joint, joint_path ); + + std::vector<FCurve*>::iterator iter; + //Add the curves of the current animation to the object + for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { + FCurve * fcu = *iter; + if (ob->type == OB_ARMATURE) + add_bone_fcurve( ob, node , fcu ); + else + BLI_addtail(AnimCurves, fcu); + } + } + std::sort(frames.begin(), frames.end()); + } + if (is_rotation || is_matrix) { + if (is_joint) + { + bPoseChannel *chan = get_pose_channel(ob->pose, bone_name); + chan->rotmode = ROT_MODE_EUL; + } + else + { + ob->rotmode = ROT_MODE_EUL; + } + } + } + +} + +//Check if object is animated by checking if animlist_map holds the animlist_id of node transforms +bool AnimationImporter::is_object_animated ( const COLLADAFW::Node * node ) +{ + bool exists = false; + const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations(); + + //for each transformation in node + for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) { + COLLADAFW::Transformation *transform = nodeTransforms[i]; + const COLLADAFW::UniqueId& listid = transform->getAnimationList(); + + //check if transformation has animations + if (animlist_map.find(listid) == animlist_map.end()) continue ; + else + { + exists = true; + break; + } + } + + return exists; +} +//XXX Is not used anymore. +void AnimationImporter::find_frames_old(std::vector<float> * frames, COLLADAFW::Node * node , COLLADAFW::Transformation::TransformationType tm_type) +{ + bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; // for each <rotate>, <translate>, etc. there is a separate Transformation - const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); + const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations(); unsigned int i; - // find frames at which to sample plus convert all rotation keys to radians - for (i = 0; i < tms.getCount(); i++) { - COLLADAFW::Transformation *tm = tms[i]; - COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + for (i = 0; i < nodeTransforms.getCount(); i++) { + COLLADAFW::Transformation *transform = nodeTransforms[i]; + COLLADAFW::Transformation::TransformationType nodeTmType = transform->getTransformationType(); - if (type == tm_type) { - const COLLADAFW::UniqueId& listid = tm->getAnimationList(); + if (nodeTmType == tm_type) { + //get animation bindings for the current transformation + const COLLADAFW::UniqueId& listid = transform->getAnimationList(); + //if transform is animated its animlist must exist. if (animlist_map.find(listid) != animlist_map.end()) { + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); - + if (bindings.getCount()) { + //for each AnimationBinding get the fcurves which animate the transform for (unsigned int j = 0; j < bindings.getCount(); j++) { std::vector<FCurve*>& curves = curve_map[bindings[j].animation]; - bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); + bool xyz = ((nodeTmType == COLLADAFW::Transformation::TRANSLATE || nodeTmType == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) { std::vector<FCurve*>::iterator iter; for (iter = curves.begin(); iter != curves.end(); iter++) { FCurve *fcu = *iter; - + + //if transform is rotation the fcurves values must be turned in to radian. if (is_rotation) fcurve_deg_to_rad(fcu); for (unsigned int k = 0; k < fcu->totvert; k++) { + //get frame value from bezTriple float fra = fcu->bezt[k].vec[1][0]; - if (std::find(frames.begin(), frames.end(), fra) == frames.end()) - frames.push_back(fra); + //if frame already not added add frame to frames + if (std::find(frames->begin(), frames->end(), fra) == frames->end()) + frames->push_back(fra); } } } @@ -583,7 +860,38 @@ Object *AnimationImporter::translate_animation(COLLADAFW::Node *node, } } } +} + + +// prerequisites: +// animlist_map - map animlist id -> animlist +// curve_map - map anim id -> curve(s) +Object *AnimationImporter::translate_animation(COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Object*>& object_map, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, + COLLADAFW::Transformation::TransformationType tm_type, + Object *par_job) +{ + + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; + bool is_joint = node->getType() == COLLADAFW::Node::JOINT; + + COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; + Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; + const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; + if (!ob) { + fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str()); + return NULL; + } + // frames at which to sample + std::vector<float> frames; + + find_frames_old(&frames, node , tm_type); + + unsigned int i; + float irest_dae[4][4]; float rest[4][4], irest[4][4]; @@ -664,7 +972,6 @@ Object *AnimationImporter::translate_animation(COLLADAFW::Node *node, BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str); else strcpy(rna_path, tm_str); - newcu[i] = create_fcurve(axis, rna_path); #ifdef ARMATURE_TEST diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index 05347a1fbc1..1e005b5c341 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -94,16 +94,35 @@ public: #if 0 virtual void change_eul_to_quat(Object *ob, bAction *act); #endif + + void translate_Animations_NEW ( COLLADAFW::Node * Node , + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, + std::map<COLLADAFW::UniqueId, Object*>& object_map ); + bool is_object_animated ( const COLLADAFW::Node * node ) ; + + + void Assign_transform_animations(std::vector<float>* frames, + COLLADAFW::Transformation* transform , + const COLLADAFW::AnimationList::AnimationBinding * binding, + std::vector<FCurve*>* curves, bool is_joint, char * joint_path); + + /*void Assign_transform_animations(std::vector<float>* frames, + COLLADAFW::Transformation *transform , + COLLADAFW::AnimationList::AnimationBinding * binding, + COLLADAFW::Node * node);*/ + void modify_fcurve(std::vector<FCurve*>* curves , char* rna_path , int array_index ); // prerequisites: // animlist_map - map animlist id -> animlist // curve_map - map anim id -> curve(s) - Object *translate_animation(COLLADAFW::Node *node, + Object * translate_animation(COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Object*>& object_map, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, COLLADAFW::Transformation::TransformationType tm_type, Object *par_job = NULL); - + + void find_frames( std::vector<float>* frames , std::vector<FCurve*>* curves ); + void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type ); // internal, better make it private // warning: evaluates only rotation // prerequisites: animlist_map, curve_map diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index 8b8e89fd4f5..48e0d99535b 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -78,6 +78,67 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node); return &joint_index_to_joint_info_map[joint_index]; } #endif +void ArmatureImporter::create_unskinned_bone( COLLADAFW::Node *node, EditBone *parent, int totchild, + float parent_mat[][4], bArmature *arm) +{ + float mat[4][4]; + float obmat[4][4]; + + // object-space + get_node_mat(obmat, node, NULL, NULL); + + // get world-space + if (parent) + mul_m4_m4m4(mat, obmat, parent_mat); + else + copy_m4_m4(mat, obmat); + + EditBone *bone = ED_armature_edit_bone_add(arm, (char*)bc_get_joint_name(node)); + totbone++; + + if (parent) bone->parent = parent; + + // set head + copy_v3_v3(bone->head, mat[3]); + + // set tail, don't set it to head because 0-length bones are not allowed + float vec[3] = {0.0f, 0.5f, 0.0f}; + add_v3_v3v3(bone->tail, bone->head, vec); + + // set parent tail + if (parent && totchild == 1) { + copy_v3_v3(parent->tail, bone->head); + + // not setting BONE_CONNECTED because this would lock child bone location with respect to parent + // bone->flag |= BONE_CONNECTED; + + // XXX increase this to prevent "very" small bones? + const float epsilon = 0.000001f; + + // derive leaf bone length + float length = len_v3v3(parent->head, parent->tail); + if ((length < leaf_bone_length || totbone == 0) && length > epsilon) { + leaf_bone_length = length; + } + + // treat zero-sized bone like a leaf bone + if (length <= epsilon) { + add_leaf_bone(parent_mat, parent); + } + + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + create_unskinned_bone( children[i], bone, children.getCount(), mat, arm); + } + + // in second case it's not a leaf bone, but we handle it the same way + if (!children.getCount() || children.getCount() > 1) { + add_leaf_bone(mat, bone); + } + +} void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[][4], bArmature *arm) @@ -300,6 +361,47 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) return armature_joints.back(); } #endif +void ArmatureImporter::create_armature_bones( ) +{ + std::vector<COLLADAFW::Node*>::iterator ri; + //if there is an armature created for root_joint next root_joint + for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { + if ( get_armature_for_joint(*ri) != NULL ) continue; + + //add armature object for current joint + //Object *ob_arm = add_object(scene, OB_ARMATURE); + + Object *ob_arm = joint_parent_map[(*ri)->getUniqueId()]; + //ob_arm->type = OB_ARMATURE; + ED_armature_to_edit(ob_arm); + + // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix + + // create unskinned bones + /* + TODO: + check if bones have already been created for a given joint + */ + leaf_bone_length = FLT_MAX; + create_unskinned_bone(*ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data); + + fix_leaf_bones(); + + // exit armature edit mode + + + //if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && ob_arm->parent!=NULL) + // ob_arm->parent = joint_parent_map[(*ri)->getUniqueId()]; + + unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; + + ED_armature_from_edit(ob_arm); + ED_armature_edit_free(ob_arm); + DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA); + } + + +} void ArmatureImporter::create_armature_bones(SkinInfo& skin) { @@ -373,7 +475,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) if (shared) ob_arm = skin.set_armature(shared); else - ob_arm = skin.create_armature(scene); + ob_arm = skin.create_armature(scene); //once for every armature // enter armature edit mode ED_armature_to_edit(ob_arm); @@ -413,21 +515,24 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA); // set_leaf_bone_shapes(ob_arm); - // set_euler_rotmode(); + // set_euler_rotmode(); } // root - if this joint is the top joint in hierarchy, if a joint // is a child of a node (not joint), root should be true since // this is where we build armature bones from -void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent) + +void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce) { joint_by_uid[node->getUniqueId()] = node; if (root) { root_joints.push_back(node); - if (parent) + if (parent) { + joint_parent_map[node->getUniqueId()] = parent; + } } } @@ -472,6 +577,9 @@ void ArmatureImporter::make_armatures(bContext *C) // free memory stolen from SkinControllerData skin.free(); } + + create_armature_bones(); + } #if 0 @@ -566,7 +674,12 @@ Object *ArmatureImporter::get_armature_for_joint(COLLADAFW::Node *node) if (skin.uses_joint_or_descendant(node)) return skin.get_armature(); } - + + std::map<COLLADAFW::UniqueId, Object*>::iterator arm; + for (arm = unskinned_armature_map.begin(); arm != unskinned_armature_map.end(); arm++) { + if(arm->first == node->getUniqueId() ) + return arm->second; + } return NULL; } diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index d36bccf7e57..f9cb09dca19 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -89,6 +89,7 @@ private: std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints std::vector<COLLADAFW::Node*> root_joints; std::map<COLLADAFW::UniqueId, Object*> joint_parent_map; + std::map<COLLADAFW::UniqueId, Object*> unskinned_armature_map; MeshImporterBase *mesh_importer; AnimationImporterBase *anim_importer; @@ -105,6 +106,9 @@ private: void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, float parent_mat[][4], bArmature *arm); + void create_unskinned_bone(COLLADAFW::Node *node, EditBone *parent, int totchild, + float parent_mat[][4], bArmature *arm); + void add_leaf_bone(float mat[][4], EditBone *bone); void fix_leaf_bones(); @@ -123,6 +127,7 @@ private: #endif void create_armature_bones(SkinInfo& skin); + void create_armature_bones( ); public: @@ -132,7 +137,7 @@ public: // root - if this joint is the top joint in hierarchy, if a joint // is a child of a node (not joint), root should be true since // this is where we build armature bones from - void add_joint(COLLADAFW::Node *node, bool root, Object *parent); + void add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce); #if 0 void add_root_joint(COLLADAFW::Node *node); diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt index 07da532146f..260dd1a7073 100644 --- a/source/blender/collada/CMakeLists.txt +++ b/source/blender/collada/CMakeLists.txt @@ -62,6 +62,7 @@ endif() set(SRC AnimationImporter.cpp + AnimationExporter.cpp ArmatureExporter.cpp ArmatureImporter.cpp CameraExporter.cpp @@ -84,6 +85,7 @@ set(SRC collada_utils.cpp AnimationImporter.h + AnimationExporter.h ArmatureExporter.h ArmatureImporter.h CameraExporter.h diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 00daac60281..0bdf41f15eb 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -114,6 +114,7 @@ extern char build_rev[]; #include "TransformWriter.h" #include "ArmatureExporter.h" +#include "AnimationExporter.h" #include "CameraExporter.h" #include "EffectExporter.h" #include "GeometryExporter.h" @@ -298,636 +299,6 @@ public: // TODO: it would be better to instantiate animations rather than create a new one per object // COLLADA allows this through multiple <channel>s in <animation>. // For this to work, we need to know objects that use a certain action. -class AnimationExporter: COLLADASW::LibraryAnimations -{ - Scene *scene; - COLLADASW::StreamWriter *sw; - -public: - - AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; } - - - - void exportAnimations(Scene *sce) - { - if(hasAnimations(sce)) { - this->scene = sce; - - openLibrary(); - - forEachObjectInScene(sce, *this); - - closeLibrary(); - } - } - - // called for each exported object - void operator() (Object *ob) - { - if (!ob->adt || !ob->adt->action) return; - - FCurve *fcu = (FCurve*)ob->adt->action->curves.first; - - if (ob->type == OB_ARMATURE) { - if (!ob->data) return; - - bArmature *arm = (bArmature*)ob->data; - for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) - write_bone_animation(ob, bone); - } - else { - while (fcu) { - // TODO "rotation_quaternion" is also possible for objects (although euler is default) - if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) || - (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)) - dae_animation(fcu, id_name(ob)); - - fcu = fcu->next; - } - } - } - -protected: - - void dae_animation(FCurve *fcu, std::string ob_name) - { - const char *axis_names[] = {"X", "Y", "Z"}; - const char *axis_name = NULL; - char anim_id[200]; - - if (fcu->array_index < 3) - axis_name = axis_names[fcu->array_index]; - - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), - fcu->rna_path, axis_names[fcu->array_index]); - - // check rna_path is one of: rotation, scale, location - - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); - - // create input source - std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name); - - // create output source - std::string output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name); - - // create interpolations source - std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name); - - std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; - COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); - std::string empty; - sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); - sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); - - // this input is required - sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); - - addSampler(sampler); - - std::string target = translate_id(ob_name) - + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true); - addChannel(COLLADABU::URI(empty, sampler_id), target); - - closeAnimation(); - } - - void write_bone_animation(Object *ob_arm, Bone *bone) - { - if (!ob_arm->adt) - return; - - for (int i = 0; i < 3; i++) - sample_and_write_bone_animation(ob_arm, bone, i); - - for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) - write_bone_animation(ob_arm, child); - } - - void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) - { - bArmature *arm = (bArmature*)ob_arm->data; - int flag = arm->flag; - std::vector<float> fra; - char prefix[256]; - - BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name); - - bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); - if (!pchan) - return; - - switch (transform_type) { - case 0: - find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); - break; - case 1: - find_frames(ob_arm, fra, prefix, "scale"); - break; - case 2: - find_frames(ob_arm, fra, prefix, "location"); - break; - default: - return; - } - - // exit rest position - if (flag & ARM_RESTPOS) { - arm->flag &= ~ARM_RESTPOS; - where_is_pose(scene, ob_arm); - } - - if (fra.size()) { - float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); - sample_animation(v, fra, transform_type, bone, ob_arm); - - if (transform_type == 0) { - // write x, y, z curves separately if it is rotation - float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames"); - for (int i = 0; i < 3; i++) { - for (unsigned int j = 0; j < fra.size(); j++) - c[j] = v[j * 3 + i]; - - dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name); - } - MEM_freeN(c); - } - else { - // write xyz at once if it is location or scale - dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name); - } - - MEM_freeN(v); - } - - // restore restpos - if (flag & ARM_RESTPOS) - arm->flag = flag; - where_is_pose(scene, ob_arm); - } - - void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm) - { - bPoseChannel *pchan, *parchan = NULL; - bPose *pose = ob_arm->pose; - - pchan = get_pose_channel(pose, bone->name); - - if (!pchan) - return; - - parchan = pchan->parent; - - enable_fcurves(ob_arm->adt->action, bone->name); - - std::vector<float>::iterator it; - for (it = frames.begin(); it != frames.end(); it++) { - float mat[4][4], ipar[4][4]; - - float ctime = bsystem_time(scene, ob_arm, *it, 0.0f); - - BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM); - where_is_pose_bone(scene, ob_arm, pchan, ctime, 1); - - // compute bone local mat - if (bone->parent) { - invert_m4_m4(ipar, parchan->pose_mat); - mul_m4_m4m4(mat, pchan->pose_mat, ipar); - } - else - copy_m4_m4(mat, pchan->pose_mat); - - switch (type) { - case 0: - mat4_to_eul(v, mat); - break; - case 1: - mat4_to_size(v, mat); - break; - case 2: - copy_v3_v3(v, mat[3]); - break; - } - - v += 3; - } - - enable_fcurves(ob_arm->adt->action, NULL); - } - - // dae_bone_animation -> add_bone_animation - // (blend this into dae_bone_animation) - void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name) - { - const char *axis_names[] = {"X", "Y", "Z"}; - const char *axis_name = NULL; - char anim_id[200]; - bool is_rot = tm_type == 0; - - if (!fra.size()) - return; - - char rna_path[200]; - BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(), - tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location")); - - if (axis > -1) - axis_name = axis_names[axis]; - - std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false); - - BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(), - (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str()); - - openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING); - - // create input source - std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name); - - // create output source - std::string output_id; - if (axis == -1) - output_id = create_xyz_source(v, fra.size(), anim_id); - else - output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name); - - // create interpolations source - std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name); - - std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; - COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id); - std::string empty; - sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id)); - sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id)); - - // TODO create in/out tangents source - - // this input is required - sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); - - addSampler(sampler); - - std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; - addChannel(COLLADABU::URI(empty, sampler_id), target); - - closeAnimation(); - } - - float convert_time(float frame) - { - return FRA2TIME(frame); - } - - float convert_angle(float angle) - { - return COLLADABU::Math::Utils::radToDegF(angle); - } - - std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic) - { - switch(semantic) { - case COLLADASW::InputSemantic::INPUT: - return INPUT_SOURCE_ID_SUFFIX; - case COLLADASW::InputSemantic::OUTPUT: - return OUTPUT_SOURCE_ID_SUFFIX; - case COLLADASW::InputSemantic::INTERPOLATION: - return INTERPOLATION_SOURCE_ID_SUFFIX; - case COLLADASW::InputSemantic::IN_TANGENT: - return INTANGENT_SOURCE_ID_SUFFIX; - case COLLADASW::InputSemantic::OUT_TANGENT: - return OUTTANGENT_SOURCE_ID_SUFFIX; - default: - break; - } - return ""; - } - - void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, - COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis) - { - switch(semantic) { - case COLLADASW::InputSemantic::INPUT: - param.push_back("TIME"); - break; - case COLLADASW::InputSemantic::OUTPUT: - if (is_rot) { - param.push_back("ANGLE"); - } - else { - if (axis) { - param.push_back(axis); - } - else { - param.push_back("X"); - param.push_back("Y"); - param.push_back("Z"); - } - } - break; - case COLLADASW::InputSemantic::IN_TANGENT: - case COLLADASW::InputSemantic::OUT_TANGENT: - param.push_back("X"); - param.push_back("Y"); - break; - default: - break; - } - } - - void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length) - { - switch (semantic) { - case COLLADASW::InputSemantic::INPUT: - *length = 1; - values[0] = convert_time(bezt->vec[1][0]); - break; - case COLLADASW::InputSemantic::OUTPUT: - *length = 1; - if (rotation) { - values[0] = convert_angle(bezt->vec[1][1]); - } - else { - values[0] = bezt->vec[1][1]; - } - break; - case COLLADASW::InputSemantic::IN_TANGENT: - case COLLADASW::InputSemantic::OUT_TANGENT: - // XXX - *length = 2; - break; - default: - *length = 0; - break; - } - } - - std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) - { - std::string source_id = anim_id + get_semantic_suffix(semantic); - - //bool is_rotation = !strcmp(fcu->rna_path, "rotation"); - bool is_rotation = false; - - if (strstr(fcu->rna_path, "rotation")) is_rotation = true; - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fcu->totvert); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, is_rotation, axis_name); - - source.prepareToAppendValues(); - - for (unsigned int i = 0; i < fcu->totvert; i++) { - float values[3]; // be careful! - int length = 0; - - get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length); - for (int j = 0; j < length; j++) - source.appendValues(values[j]); - } - - source.finish(); - - return source_id; - } - - std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name) - { - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(tot); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, is_rot, axis_name); - - source.prepareToAppendValues(); - - for (int i = 0; i < tot; i++) { - float val = v[i]; - if (semantic == COLLADASW::InputSemantic::INPUT) - val = convert_time(val); - else if (is_rot) - val = convert_angle(val); - source.appendValues(val); - } - - source.finish(); - - return source_id; - } - - std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name) - { - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fra.size()); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, is_rot, axis_name); - - source.prepareToAppendValues(); - - std::vector<float>::iterator it; - for (it = fra.begin(); it != fra.end(); it++) { - float val = *it; - if (semantic == COLLADASW::InputSemantic::INPUT) - val = convert_time(val); - else if (is_rot) - val = convert_angle(val); - source.appendValues(val); - } - - source.finish(); - - return source_id; - } - - // only used for sources with OUTPUT semantic - std::string create_xyz_source(float *v, int tot, const std::string& anim_id) - { - COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; - std::string source_id = anim_id + get_semantic_suffix(semantic); - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(tot); - source.setAccessorStride(3); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - add_source_parameters(param, semantic, false, NULL); - - source.prepareToAppendValues(); - - for (int i = 0; i < tot; i++) { - source.appendValues(*v, *(v + 1), *(v + 2)); - v += 3; - } - - source.finish(); - - return source_id; - } - - std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name) - { - std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION); - - COLLADASW::NameSource source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(tot); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("INTERPOLATION"); - - source.prepareToAppendValues(); - - for (int i = 0; i < tot; i++) { - source.appendValues(LINEAR_NAME); - } - - source.finish(); - - return source_id; - } - - // for rotation, axis name is always appended and the value of append_axis is ignored - std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis) - { - std::string tm_name; - - // when given rna_path, determine tm_type from it - if (rna_path) { - char *name = extract_transform_name(rna_path); - - if (strstr(name, "rotation")) - tm_type = 0; - else if (!strcmp(name, "scale")) - tm_type = 1; - else if (!strcmp(name, "location")) - tm_type = 2; - else - tm_type = -1; - } - - switch (tm_type) { - case 0: - return std::string("rotation") + std::string(axis_name) + ".ANGLE"; - case 1: - tm_name = "scale"; - break; - case 2: - tm_name = "location"; - break; - default: - tm_name = ""; - break; - } - - if (tm_name.size()) { - if (append_axis) - return tm_name + std::string(".") + std::string(axis_name); - else - return tm_name; - } - - return std::string(""); - } - - char *extract_transform_name(char *rna_path) - { - char *dot = strrchr(rna_path, '.'); - return dot ? (dot + 1) : rna_path; - } - - void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name) - { - FCurve *fcu= (FCurve*)ob->adt->action->curves.first; - - for (; fcu; fcu = fcu->next) { - if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix))) - continue; - - char *name = extract_transform_name(fcu->rna_path); - if (!strcmp(name, tm_name)) { - for (unsigned int i = 0; i < fcu->totvert; i++) { - float f = fcu->bezt[i].vec[1][0]; - if (std::find(fra.begin(), fra.end(), f) == fra.end()) - fra.push_back(f); - } - } - } - - // keep the keys in ascending order - std::sort(fra.begin(), fra.end()); - } - - void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode) - { - if (rotmode > 0) - find_frames(ob, fra, prefix, "rotation_euler"); - else if (rotmode == ROT_MODE_QUAT) - find_frames(ob, fra, prefix, "rotation_quaternion"); - /*else if (rotmode == ROT_MODE_AXISANGLE) - ;*/ - } - - // enable fcurves driving a specific bone, disable all the rest - // if bone_name = NULL enable all fcurves - void enable_fcurves(bAction *act, char *bone_name) - { - FCurve *fcu; - char prefix[200]; - - if (bone_name) - BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); - - for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) { - if (bone_name) { - if (!strncmp(fcu->rna_path, prefix, strlen(prefix))) - fcu->flag &= ~FCURVE_DISABLED; - else - fcu->flag |= FCURVE_DISABLED; - } - else { - fcu->flag &= ~FCURVE_DISABLED; - } - } - } - - bool hasAnimations(Scene *sce) - { - Base *base= (Base*) sce->base.first; - while(base) { - Object *ob = base->object; - - FCurve *fcu = 0; - if(ob->adt && ob->adt->action) - fcu = (FCurve*)ob->adt->action->curves.first; - - if ((ob->type == OB_ARMATURE && ob->data) || fcu) { - return true; - } - base= base->next; - } - return false; - } -}; void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename) { diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 78ee444bb4e..14ce9a9b417 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -250,12 +250,13 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW unsigned int i; Object *ob; - for (i = 0; i < 4; i++) - ob = anim_importer.translate_animation(node, object_map, root_map, types[i]); + //for (i = 0; i < 4; i++) + //ob = + anim_importer.translate_Animations_NEW(node, root_map, object_map); COLLADAFW::NodePointerArray &children = node->getChildNodes(); for (i = 0; i < children.getCount(); i++) { - translate_anim_recursive(children[i], node, ob); + translate_anim_recursive(children[i], node, NULL); } } @@ -382,7 +383,14 @@ void DocumentImporter::write_node (COLLADAFW::Node *node, COLLADAFW::Node *paren bool is_joint = node->getType() == COLLADAFW::Node::JOINT; if (is_joint) { - armature_importer.add_joint(node, parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT, par); + if ( par ) { + Object * empty = par; + par = add_object(sce, OB_ARMATURE); + bc_set_parent(par,empty->parent, mContext); + //remove empty : todo + object_map[parent_node->getUniqueId()] = par; + } + armature_importer.add_joint(node, parent_node == NULL || parent_node->getType() != COLLADAFW::Node::JOINT, par, sce); } else { COLLADAFW::InstanceGeometryPointerArray &geom = node->getInstanceGeometries(); diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index 83b9449c8f2..ce0d561c524 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -308,11 +308,15 @@ void SkinInfo::find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints std::vector<COLLADAFW::Node*>& result) { std::vector<COLLADAFW::Node*>::const_iterator it; + // for each root_joint for (it = root_joints.begin(); it != root_joints.end(); it++) { COLLADAFW::Node *root = *it; std::vector<JointData>::iterator ji; + //for each joint_data in this skin for (ji = joint_data.begin(); ji != joint_data.end(); ji++) { + //get joint node from joint map COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid]; + //find if joint node is in the tree belonging to the root_joint if (find_node_in_tree(joint, root)) { if (std::find(result.begin(), result.end(), root) == result.end()) result.push_back(root); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 9145cc2b79d..9eb9e3ecd9a 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -38,7 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" - +#include "BKE_library.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -515,12 +515,34 @@ void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve * * - Drivers * - TODO... some others? */ - if (fcu->grp) - action_groups_remove_channel(adt->action, fcu); - else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) + if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) { + /* driver F-Curve */ BLI_remlink(&adt->drivers, fcu); - else if (adt->action) - BLI_remlink(&adt->action->curves, fcu); + } + else if (adt->action) { + /* remove from group or action, whichever one "owns" the F-Curve */ + if (fcu->grp) + action_groups_remove_channel(adt->action, fcu); + else + BLI_remlink(&adt->action->curves, fcu); + + /* if action has no more F-Curves as a result of this, unlink it from + * AnimData if it did not come from a NLA Strip being tweaked. + * + * This is done so that we don't have dangling Object+Action entries in + * channel list that are empty, and linger around long after the data they + * are for has disappeared (and probably won't come back). + */ + // XXX: does everybody always want this? + /* XXX: there's a problem where many actions could build up in the file if multiple + * full add/delete cycles are performed on the same objects, but assume that this is rare + */ + if ((adt->action->curves.first == NULL) && (adt->flag & ADT_NLA_EDIT_ON)==0) + { + id_us_min(&adt->action->id); + adt->action = NULL; + } + } /* free the F-Curve itself */ free_fcurve(fcu); diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index c6e55427034..1fb2317cdbb 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -1500,3 +1500,14 @@ void ED_marker_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0); #endif } + +/* to be called from animation editor keymaps, see note below */ +void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap) +{ + /* duplicate of some marker-hotkeys but without the bounds checking + * since these are handy to be able to do unrestricted and won't conflict + * with primary function hotkeys (Usability tweak [#27469]) + */ + WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0); +} diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 954928fc486..8197d6b25dd 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -604,7 +604,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - uiLayout *box, *row, *subrow; + uiLayout *box, *row, *subrow, *col; uiBlock *block; uiBut *but; short width= 314; @@ -622,7 +622,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie block= uiLayoutGetBlock(row); // err... /* left-align -------------------------------------------- */ - subrow= uiLayoutRow(row, 0); + subrow= uiLayoutRow(row, 1); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT); uiBlockSetEmboss(block, UI_EMBOSSN); @@ -640,7 +640,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie uiItemL(subrow, "<Unknown Modifier>", ICON_NONE); /* right-align ------------------------------------------- */ - subrow= uiLayoutRow(row, 0); + subrow= uiLayoutRow(row, 1); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT); @@ -694,6 +694,44 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie default: /* unknown type */ break; } + + /* one last panel below this: FModifier range */ + // TODO: experiment with placement of this + { + box = uiLayoutBox(layout); + + /* restricted range ----------------------------------------------------- */ + col = uiLayoutColumn(box, 1); + + /* top row: use restricted range */ + row= uiLayoutRow(col, 1); + uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); + + if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { + /* second row: settings */ + row = uiLayoutRow(col, 1); + + uiItemR(row, &ptr, "frame_start", 0, "Start", ICON_NONE); + uiItemR(row, &ptr, "frame_end", 0, "End", ICON_NONE); + + /* third row: blending influence */ + row = uiLayoutRow(col, 1); + + uiItemR(row, &ptr, "blend_in", 0, "In", ICON_NONE); + uiItemR(row, &ptr, "blend_out", 0, "Out", ICON_NONE); + } + + /* influence -------------------------------------------------------------- */ + col = uiLayoutColumn(box, 1); + + /* top row: use influence */ + uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE); + + if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) { + /* second row: influence value */ + uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE); + } + } } } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index f111339b963..e2afda04d30 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -111,7 +111,7 @@ void delete_fcurve_keys(FCurve *fcu) { int i; - if(fcu->bezt==NULL) /* ignore baked curves */ + if (fcu->bezt==NULL) /* ignore baked curves */ return; /* Delete selected BezTriples */ @@ -124,7 +124,7 @@ void delete_fcurve_keys(FCurve *fcu) } /* Free the array of BezTriples if there are not keyframes */ - if(fcu->totvert == 0) + if (fcu->totvert == 0) clear_fcurve_keys(fcu); } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index c525c9af626..69e7c4eb73a 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -224,6 +224,7 @@ static int add_empty_ks_path_exec (bContext *C, wmOperator *op) ksp->groupmode= KSP_GROUP_KSNAME; // XXX? ksp->idtype= ID_OB; + ksp->flag= KSP_FLAG_WHOLE_ARRAY; return OPERATOR_FINISHED; } @@ -782,19 +783,19 @@ void ANIM_keying_sets_menu_setup (bContext *C, const char title[], const char op * - these are listed in the order in which they were defined for the active scene */ if (scene->keyingsets.first) { - for (ks= scene->keyingsets.first; ks; ks= ks->next) { + for (ks= scene->keyingsets.first; ks; ks=ks->next, i++) { if (ANIM_keyingset_context_ok_poll(C, ks)) - uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i++); + uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i); } uiItemS(layout); } /* builtin Keying Sets */ i= -1; - for (ks= builtin_keyingsets.first; ks; ks= ks->next) { + for (ks= builtin_keyingsets.first; ks; ks=ks->next, i--) { /* only show KeyingSet if context is suitable */ if (ANIM_keyingset_context_ok_poll(C, ks)) - uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i--); + uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i); } uiPupMenuEnd(C, pup); diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 8176aa5893b..fa5fecbd9d0 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -1002,6 +1002,14 @@ static int pose_paste_exec (bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + /* if selOnly option is enabled, if user hasn't selected any bones, + * just go back to default behaviour to be more in line with other pose tools + */ + if (selOnly) { + if (CTX_DATA_COUNT(C, selected_pose_bones) == 0) + selOnly = 0; + } + /* Safely merge all of the channels in the buffer pose into any existing pose */ for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) { if (chan->flag & POSE_KEY) { @@ -1169,7 +1177,7 @@ void POSE_OT_paste (wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "flipped", 0, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose"); - RNA_def_boolean(ot->srna, "selected_mask", 0, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose"); + RNA_def_boolean(ot->srna, "selected_mask", 1, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose"); } /* ********************************************** */ diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h index f804e052301..a8e91add348 100644 --- a/source/blender/editors/include/ED_markers.h +++ b/source/blender/editors/include/ED_markers.h @@ -34,6 +34,7 @@ #define ED_MARKERS_H struct wmKeyConfig; +struct wmKeyMap; struct bContext; struct bAnimContext; struct Scene; @@ -72,6 +73,9 @@ void ED_operatortypes_marker(void); /* called in screen_ops.c:ED_keymap_screen() */ void ED_marker_keymap(struct wmKeyConfig *keyconf); +/* called in animation editors - keymap defines */ +void ED_marker_keymap_animedit_conflictfree(struct wmKeyMap *keymap); + /* debugging only */ void debug_markers_print_list(struct ListBase *markers); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 2e4106b3c04..1352648b271 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -295,6 +295,7 @@ void uiStyleInit(void) { uiFont *font= U.uifonts.first; uiStyle *style= U.uistyles.first; + int defaultFontId = -1; /* recover from uninitialized dpi */ if(U.dpi == 0) @@ -314,6 +315,7 @@ void uiStyleInit(void) if(font->uifont_id==UIFONT_DEFAULT) { font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size); + defaultFontId = font->blf_id; } else { font->blf_id= BLF_load(font->filename); @@ -351,6 +353,14 @@ void uiStyleInit(void) blf_mono_font_render= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size); BLF_size(blf_mono_font_render, 12, 72); + + /* also another copy of default for rendering else we get threading problems */ + if (defaultFontId != -1) { + if (blf_default_font_render == -1) + blf_default_font_render= BLF_load_mem_unique("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size); + + BLF_size(blf_default_font_render, 12, 72); + } } void uiStyleFontSet(uiFontStyle *fs) diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 3f825762d74..7cb274f04c6 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -663,7 +663,7 @@ void ui_theme_init_default(void) SETCOL(btheme->tipo.handle_vertex, 0, 0, 0, 255); SETCOL(btheme->tipo.handle_vertex_select, 255, 133, 0, 255); - btheme->tipo.handle_vertex_size= 3; + btheme->tipo.handle_vertex_size= 4; SETCOL(btheme->tipo.ds_channel, 82, 96, 110, 255); SETCOL(btheme->tipo.ds_subchannel, 124, 137, 150, 255); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 450bd70a568..a3df25824a4 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -567,7 +567,8 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int } con = constraints_findByName(list, constraint_name); - printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>"); + //if (G.f & G_DEBUG) + //printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>"); if (con && (type != 0) && (con->type != type)) con = NULL; diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 6c3f80cda41..2ccad308676 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -40,6 +40,7 @@ #include "BLI_blenlib.h" #include "ED_anim_api.h" +#include "ED_markers.h" #include "ED_transform.h" #include "action_intern.h" @@ -162,7 +163,7 @@ static void action_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) /* menu + set setting */ WM_keymap_add_item(keymap, "ACTION_OT_handle_type", VKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "ACTION_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "ACTION_OT_interpolation_type", TKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "ACTION_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0); @@ -193,6 +194,9 @@ static void action_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) /* transform system */ transform_keymap_for_space(keyconf, keymap, SPACE_ACTION); + + /* special markers hotkeys for anim editors: see note in definition of this function */ + ED_marker_keymap_animedit_conflictfree(keymap); } /* --------------- */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index fb1144b4fa8..3073ff13075 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -472,7 +472,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar * uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA); } - uiItemR(col, &dtar_ptr, "use_local_space_transform", 0, NULL, ICON_NONE); + uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE); col= uiLayoutColumn(layout, 1); uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", "Ob/Bone 2:"); @@ -484,7 +484,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar * uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA); } - uiItemR(col, &dtar2_ptr, "use_local_space_transform", 0, NULL, ICON_NONE); + uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE); } /* settings for 'transform channel' driver variable type */ @@ -493,7 +493,7 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar DriverTarget *dtar= &dvar->targets[0]; Object *ob = (Object *)dtar->id; PointerRNA dtar_ptr; - uiLayout *col, *row; + uiLayout *col, *subcol; /* initialise RNA pointer to the target */ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); @@ -509,9 +509,9 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA); } - row= uiLayoutRow(layout, 1); - uiItemR(row, &dtar_ptr, "transform_type", 0, "", ICON_NONE); - uiItemR(row, &dtar_ptr, "use_local_space_transform", 0, NULL, ICON_NONE); + subcol= uiLayoutColumn(layout, 1); + uiItemR(subcol, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE); + uiItemR(subcol, &dtar_ptr, "transform_space", 0, "Space", ICON_NONE); } /* driver settings for active F-Curve (only for 'Drivers' mode) */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 962cadba1f3..0da03832d15 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2248,7 +2248,7 @@ void GRAPH_OT_fmodifier_paste (wmOperatorType *ot) /* api callbacks */ ot->exec= graph_fmodifier_paste_exec; - ot->poll= graphop_editable_keyframes_poll; + ot->poll= graphop_active_fcurve_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 03cc8bb9e80..0d7cdf94bc7 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -46,6 +46,7 @@ #include "UI_view2d.h" #include "ED_anim_api.h" +#include "ED_markers.h" #include "ED_screen.h" #include "ED_transform.h" @@ -361,7 +362,7 @@ static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) WM_keymap_add_item(keymap, "GRAPH_OT_handle_type", VKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, 0, 0); /* destructive */ WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0); @@ -399,6 +400,9 @@ static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) /* transform system */ transform_keymap_for_space(keyconf, keymap, SPACE_IPO); + + /* special markers hotkeys for anim editors: see note in definition of this function */ + ED_marker_keymap_animedit_conflictfree(keymap); } /* --------------- */ diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 019ce2a714a..c1fc27eb9f3 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -3677,16 +3677,22 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; PointerRNA settings_ptr; - uiLayout *row; + uiLayout *row, *subrow, *col;; - if(ob->type != OB_ARMATURE){ - uiItemL(layout, "Actuator only available for armatures", ICON_NONE); - return; - } RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr); row= uiLayoutRow(layout, 0); uiItemR(row, ptr, "play_mode", 0, "", ICON_NONE); + + subrow= uiLayoutRow(row, 1); + uiItemR(subrow, ptr, "use_force", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + uiItemR(subrow, ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + col = uiLayoutColumn(subrow, 0); + uiLayoutSetActive(col, (RNA_boolean_get(ptr, "use_additive") || RNA_boolean_get(ptr, "use_force"))); + uiItemR(col, ptr, "use_local", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + row= uiLayoutRow(layout, 0); uiItemR(row, ptr, "action", 0, "", ICON_NONE); uiItemR(row, ptr, "use_continue_last_frame", 0, NULL, ICON_NONE); @@ -3699,11 +3705,16 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) uiItemR(row, ptr, "frame_end", 0, NULL, ICON_NONE); } + uiItemR(row, ptr, "apply_to_children", 0, NULL, ICON_NONE); + row= uiLayoutRow(layout, 0); uiItemR(row, ptr, "frame_blend_in", 0, NULL, ICON_NONE); uiItemR(row, ptr, "priority", 0, NULL, ICON_NONE); row= uiLayoutRow(layout, 0); + uiItemR(row, ptr, "layer", 0, NULL, ICON_NONE); + + row= uiLayoutRow(layout, 0); uiItemPointerR(layout, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE); #ifdef __NLA_ACTION_BY_MOTION_ACTUATOR @@ -3977,6 +3988,7 @@ static void draw_actuator_game(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, ptr, "filename", 0, NULL, ICON_NONE); } +/* The IPO/Fcurve actuator has been deprecated, so this is no longer used */ static void draw_actuator_ipo(uiLayout *layout, PointerRNA *ptr) { Object *ob; @@ -4397,9 +4409,6 @@ static void draw_brick_actuator(uiLayout *layout, PointerRNA *ptr, bContext *C) case ACT_GAME: draw_actuator_game(box, ptr); break; - case ACT_IPO: - draw_actuator_ipo(box, ptr); - break; case ACT_MESSAGE: draw_actuator_message(box, ptr, C); break; diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 85dcf14adac..ea8e8961f02 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -45,6 +45,7 @@ #include "BKE_screen.h" #include "ED_anim_api.h" +#include "ED_markers.h" #include "ED_screen.h" #include "ED_transform.h" @@ -262,6 +263,9 @@ static void nla_keymap_main (wmKeyConfig *keyconf, wmKeyMap *keymap) /* transform system */ transform_keymap_for_space(keyconf, keymap, SPACE_NLA); + + /* special markers hotkeys for anim editors: see note in definition of this function */ + ED_marker_keymap_animedit_conflictfree(keymap); } /* --------------- */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 119c5da309e..e1efd5b4622 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -127,6 +127,7 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[ case SEQ_GLOW: case SEQ_MULTICAM: case SEQ_ADJUSTMENT: + case SEQ_TITLECARD: UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); /* slightly offset hue to distinguish different effects */ diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index c8965c4d3db..46638007fb1 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -98,9 +98,10 @@ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"}, {SEQ_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"}, {SEQ_COLOR, "COLOR", 0, "Color", "Color effect strip type"}, - {SEQ_SPEED, "SPEED", 0, "Speed", "Color effect strip type"}, + {SEQ_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TITLECARD, "TITLE_CARD", 0, "Title Card", ""}, {0, NULL, 0, NULL, NULL} }; @@ -408,6 +409,7 @@ int event_to_efftype(int event) if(event==16) return SEQ_COLOR; if(event==17) return SEQ_SPEED; if(event==18) return SEQ_ADJUSTMENT; + if(event==19) return SEQ_TITLECARD; return 0; } @@ -520,7 +522,8 @@ static void change_sequence(Scene *scene) "|Transform%x15" "|Color Generator%x16" "|Speed Control%x17" - "|Adjustment Layer%x18"); + "|Adjustment Layer%x18" + "|Title Card%x19"); if(event > 0) { if(event==1) { SWAP(Sequence *,last_seq->seq1,last_seq->seq2); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 625e5561389..28230b7a48b 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -907,9 +907,12 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) void text_drawcache_tag_update(SpaceText *st, int full) { - DrawCache *drawcache= (DrawCache *)st->drawcache; - - if(drawcache) { + /* this happens if text editor ops are caled from python */ + if (st == NULL) + return; + + if(st->drawcache) { + DrawCache *drawcache= (DrawCache *)st->drawcache; Text *txt= st->text; if(drawcache->update_flag) { diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 02a7ea890f5..29f40ec9dd0 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -1217,6 +1217,87 @@ static void draw_b_bone(int dt, int armflag, int boneflag, int constflag, unsign } } +static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments) +{ + if ((segments > 1) && (pchan)) { + float dlen= length/(float)segments; + Mat4 *bbone = bbones; + int a; + + for (a=0; a<segments; a++, bbone++) { + glPushMatrix(); + glMultMatrixf(bbone->mat); + + glBegin(GL_LINES); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, dlen, 0.0f); + glEnd(); // GL_LINES + + glPopMatrix(); + } + } + else { + glPushMatrix(); + + glBegin(GL_LINES); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, length, 0.0f); + glEnd(); + + glPopMatrix(); + } +} + +static void draw_wire_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) +{ + Mat4 *bbones = NULL; + int segments = 0; + float length; + + if (pchan) { + segments= pchan->bone->segments; + length= pchan->bone->length; + + if (segments > 1) + bbones = b_bone_spline_setup(pchan, 0); + } + else + length= ebone->length; + + /* draw points only if... */ + if (armflag & ARM_EDITMODE) { + /* move to unitspace */ + glPushMatrix(); + glScalef(length, length, length); + draw_bone_points(dt, armflag, boneflag, id); + glPopMatrix(); + length *= 0.95f; // make vertices visible + } + + /* this chunk not in object mode */ + if (armflag & (ARM_EDITMODE|ARM_POSEMODE)) { + if (id != -1) + glLoadName((GLuint) id|BONESEL_BONE); + + draw_wire_bone_segments(pchan, bbones, length, segments); + + /* further we send no names */ + if (id != -1) + glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + } + + /* colors for modes */ + if (armflag & ARM_POSEMODE) { + set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); + } + else if (armflag & ARM_EDITMODE) { + set_ebone_glColor(boneflag); + } + + /* draw normal */ + draw_wire_bone_segments(pchan, bbones, length, segments); +} + static void draw_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, float length) { @@ -1656,7 +1737,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, int use_custom = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM); glPushMatrix(); - if(use_custom && pchan->custom_tx) { + if (use_custom && pchan->custom_tx) { glMultMatrixf(pchan->custom_tx->pose_mat); } else { @@ -1684,6 +1765,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } else if (arm->drawtype==ARM_LINE) ; /* nothing in solid */ + else if (arm->drawtype==ARM_WIRE) + ; /* nothing in solid */ else if (arm->drawtype==ARM_ENVELOPE) draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL); else if (arm->drawtype==ARM_B_BONE) @@ -1702,7 +1785,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet, * stick bones and/or wire custom-shapes are drawn in next loop */ - if ((arm->drawtype != ARM_LINE) && (draw_wire == 0)) { + if (ELEM(arm->drawtype,ARM_LINE,ARM_WIRE)==0 && (draw_wire == 0)) { /* object tag, for bordersel optim */ glLoadName(index & 0xFFFF); index= -1; @@ -1773,8 +1856,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (index != -1) index+= 0x10000; // pose bones count in higher 2 bytes only } - /* stick bones have not been drawn yet so dont clear object selection in this case */ - if ((arm->drawtype != ARM_LINE) && draw_wire) { + /* stick or wire bones have not been drawn yet so dont clear object selection in this case */ + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)==0 && draw_wire) { /* object tag, for bordersel optim */ glLoadName(index & 0xFFFF); index= -1; @@ -1784,7 +1867,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* wire draw over solid only in posemode */ if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || (arm->drawtype==ARM_LINE)) { /* draw line check first. we do selection indices */ - if (arm->drawtype==ARM_LINE) { + if ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) { if (arm->flag & ARM_POSEMODE) index= base->selcol; } @@ -1879,6 +1962,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, } else if (arm->drawtype==ARM_LINE) draw_line_bone(arm->flag, flag, constflag, index, pchan, NULL); + else if (arm->drawtype==ARM_WIRE) + draw_wire_bone(dt, arm->flag, flag, constflag, index, pchan, NULL); else if (arm->drawtype==ARM_B_BONE) draw_b_bone(OB_WIRE, arm->flag, flag, constflag, index, pchan, NULL); else @@ -2013,7 +2098,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) } /* if solid we draw it first */ - if ((dt > OB_WIRE) && (arm->drawtype!=ARM_LINE)) { + if ((dt > OB_WIRE) && (arm->drawtype != ARM_LINE)) { for (eBone=arm->edbo->first, index=0; eBone; eBone=eBone->next, index++) { if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A)==0) { @@ -2034,6 +2119,8 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); else if(arm->drawtype==ARM_B_BONE) draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); + else if (arm->drawtype==ARM_WIRE) + draw_wire_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); else { draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length); } @@ -2047,7 +2134,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) /* if wire over solid, set offset */ index= -1; glLoadName(-1); - if (arm->drawtype==ARM_LINE) { + if ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) { if(G.f & G_PICKSEL) index= 0; } @@ -2081,6 +2168,8 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) if (arm->drawtype == ARM_LINE) draw_line_bone(arm->flag, flag, 0, index, NULL, eBone); + else if (arm->drawtype==ARM_WIRE) + draw_wire_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone); else if (arm->drawtype == ARM_B_BONE) draw_b_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone); else @@ -2109,7 +2198,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt) /* restore */ if(index!=-1) glLoadName(-1); - if (arm->drawtype==ARM_LINE); + if ELEM(arm->drawtype,ARM_LINE,ARM_WIRE); else if (dt>OB_WIRE) bglPolygonOffset(rv3d->dist, 0.0f); /* finally names and axes */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 181fb0f0aac..b8369d8cbff 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1982,12 +1982,15 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu /* ******************* TRANSFORM LIMITS ********************** */ -static void constraintTransLim(TransInfo *UNUSED(t), TransData *td) +static void constraintTransLim(TransInfo *t, TransData *td) { if (td->con) { - bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); + bConstraintTypeInfo *ctiLoc= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); + bConstraintTypeInfo *ctiDist= get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); + bConstraintOb cob= {NULL}; bConstraint *con; + float ctime = (float)(t->scene->r.cfra); /* Make a temporary bConstraintOb for using these limit constraints * - they only care that cob->matrix is correctly set ;-) @@ -1998,6 +2001,8 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td) /* Evaluate valid constraints */ for (con= td->con; con; con= con->next) { + bConstraintTypeInfo *cti = NULL; + ListBase targets = {NULL, NULL}; float tmat[4][4]; /* only consider constraint if enabled */ @@ -2010,7 +2015,17 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td) if ((data->flag2 & LIMIT_TRANSFORM)==0) continue; + cti = ctiLoc; + } + else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) { + bDistLimitConstraint *data= con->data; + if ((data->flag & LIMITDIST_TRANSFORM)==0) + continue; + cti = ctiDist; + } + + if (cti) { /* do space conversions */ if (con->ownspace == CONSTRAINT_SPACE_WORLD) { /* just multiply by td->mtx (this should be ok) */ @@ -2022,8 +2037,11 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td) continue; } + /* get constraint targets if needed */ + get_constraint_targets_for_solving(con, &cob, &targets, ctime); + /* do constraint */ - cti->evaluate_constraint(con, &cob, NULL); + cti->evaluate_constraint(con, &cob, &targets); /* convert spaces again */ if (con->ownspace == CONSTRAINT_SPACE_WORLD) { @@ -2031,6 +2049,9 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td) copy_m4_m4(tmat, cob.matrix); mul_m4_m3m4(cob.matrix, td->smtx, tmat); } + + /* free targets list */ + BLI_freelistN(&targets); } } @@ -5783,8 +5804,8 @@ int TimeSlide(TransInfo *t, const int mval[2]) char str[200]; /* calculate mouse co-ordinates */ - UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); - UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); + UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &sval[0], &sval[1]); /* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */ // XXX Need to be able to repeat this diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 669c3195dfd..34d206f9d6b 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -3131,12 +3131,18 @@ static void createTransActionData(bContext *C, TransInfo *t) float min=999999999.0f, max=-999999999.0f; int i; - td= (t->data + 1); - for (i=1; i < count; i+=3, td+=3) { + td= t->data; + for (i=0; i < count; i++, td++) { if (min > *(td->val)) min= *(td->val); if (max < *(td->val)) max= *(td->val); } + if (min == max) { + /* just use the current frame ranges */ + min = (float)PSFRA; + max = (float)PEFRA; + } + /* minx/maxx values used by TimeSlide are stored as a * calloced 2-float array in t->customData. This gets freed * in postTrans (T_FREE_CUSTOMDATA). diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7bdf6c909d9..4b0a734a98e 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -897,7 +897,7 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, 0, 0); RNA_enum_set(km->ptr, "mode", TFM_TIME_SCALE); - km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", TKEY, KM_PRESS, 0, 0); + km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", TKEY, KM_PRESS, KM_SHIFT, 0); RNA_enum_set(km->ptr, "mode", TFM_TIME_SLIDE); break; case SPACE_IPO: diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 887a0300ee2..071f66cddd6 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -56,8 +56,10 @@ typedef struct bActionActuator { char frameProp[32]; /* Set this property to the actions current frame */ short blendin; /* Number of frames of blending */ short priority; /* Execution priority */ + short layer; /* Animation layer */ short end_reset; /* Ending the actuator (negative pulse) wont reset the the action to its starting frame */ short strideaxis; /* Displacement axis */ + short pad[3]; float stridelength; /* Displacement incurred by cycle */ // not in use } bActionActuator; @@ -120,6 +122,7 @@ typedef struct bObjectActuator { struct Object *reference; } bObjectActuator; +/* deprecated, handled by bActionActuator now */ typedef struct bIpoActuator { short flag, type; float sta, end; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 4b649031f97..00a9786fc6f 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -62,6 +62,11 @@ typedef struct FModifier { short flag; /* settings for the modifier */ float influence; /* the amount that the modifier should influence the value */ + + float sfra; /* start frame of restricted frame-range */ + float efra; /* end frame of restricted frame-range */ + float blendin; /* number of frames from sfra before modifier takes full influence */ + float blendout; /* number of frames from efra before modifier fades out */ } FModifier; /* Types of F-Curve modifier @@ -86,13 +91,17 @@ typedef enum eFModifier_Types { /* F-Curve Modifier Settings */ typedef enum eFModifier_Flags { /* modifier is not able to be evaluated for some reason, and should be skipped (internal) */ - FMODIFIER_FLAG_DISABLED = (1<<0), + FMODIFIER_FLAG_DISABLED = (1<<0), /* modifier's data is expanded (in UI) */ - FMODIFIER_FLAG_EXPANDED = (1<<1), + FMODIFIER_FLAG_EXPANDED = (1<<1), /* modifier is active one (in UI) for editing purposes */ - FMODIFIER_FLAG_ACTIVE = (1<<2), + FMODIFIER_FLAG_ACTIVE = (1<<2), /* user wants modifier to be skipped */ - FMODIFIER_FLAG_MUTED = (1<<3) + FMODIFIER_FLAG_MUTED = (1<<3), + /* restrict range that F-Modifier can be considered over */ + FMODIFIER_FLAG_RANGERESTRICT = (1<<4), + /* use influence control */ + FMODIFIER_FLAG_USEINFLUENCE = (1<<5) } eFModifier_Flags; /* --- */ @@ -280,8 +289,12 @@ typedef enum eDriverTarget_Flag { DTAR_FLAG_STRUCT_REF = (1<<0), /* idtype can only be 'Object' */ DTAR_FLAG_ID_OB_ONLY = (1<<1), - /* toggles localspace (where transforms are manually obtained) */ + + /* "localspace" flags */ + /* base flag - basically "pre parent+constraints" */ DTAR_FLAG_LOCALSPACE = (1<<2), + /* include constraints transformed to space including parents */ + DTAR_FLAG_LOCAL_CONSTS = (1<<3), } eDriverTarget_Flag; /* Transform Channels for Driver Targets */ diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 3547101612f..808db1f4843 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -136,7 +136,8 @@ typedef enum eArmature_Drawtype { ARM_OCTA = 0, ARM_LINE, ARM_B_BONE, - ARM_ENVELOPE + ARM_ENVELOPE, + ARM_WIRE } eArmature_Drawtype; /* armature->deformflag */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 1d752fce4ef..c2c0c6f1611 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -677,7 +677,10 @@ typedef enum eRotLimit_Flags { /* distance limit constraint */ /* bDistLimitConstraint->flag */ typedef enum eDistLimit_Flag { - LIMITDIST_USESOFT = (1<<0) + /* "soft" cushion effect when reaching the limit sphere */ // NOT IMPLEMENTED! + LIMITDIST_USESOFT = (1<<0), + /* as for all Limit constraints - allow to be used during transform? */ + LIMITDIST_TRANSFORM = (1<<1) } eDistLimit_Flag; /* bDistLimitConstraint->mode */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 3e7654bcf47..b9bea7a89b0 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -227,6 +227,14 @@ typedef struct SolidColorVars { float pad; } SolidColorVars; +typedef struct TitleCardVars { + char titlestr[64]; + char subtitle[128]; + + float fgcol[3]; + float bgcol[3]; +} TitleCardVars; + typedef struct SpeedControlVars { float * frameMap; float globalSpeed; @@ -314,7 +322,8 @@ typedef struct SpeedControlVars { #define SEQ_SPEED 29 #define SEQ_MULTICAM 30 #define SEQ_ADJUSTMENT 31 -#define SEQ_EFFECT_MAX 31 +#define SEQ_TITLECARD 40 +#define SEQ_EFFECT_MAX 40 #define STRIPELEM_FAILED 0 #define STRIPELEM_OK 1 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index ae57cf3f80b..4757c112b09 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -435,6 +435,7 @@ extern UserDef U; /* from blenkernel blender.c */ #define USER_NONEGFRAMES (1 << 24) #define USER_TXT_TABSTOSPACES_DISABLE (1 << 25) #define USER_TOOLTIPS_PYTHON (1 << 26) +#define USER_NO_RECENTLOAD_UPDATE (1 << 27) /* helper macro for checking frame clamping */ #define FRAMENUMBER_MIN_CLAMP(cfra) \ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 882fbce9271..49bc10a0675 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -534,6 +534,7 @@ extern StructRNA RNA_ThemeWidgetColors; extern StructRNA RNA_ThemeWidgetStateColors; extern StructRNA RNA_TimelineMarker; extern StructRNA RNA_Timer; +extern StructRNA RNA_TitleCardSequence; extern StructRNA RNA_ToolSettings; extern StructRNA RNA_TouchSensor; extern StructRNA RNA_TrackToConstraint; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 8fbee8ea740..a632c5c646e 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -3188,7 +3188,7 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int /* 2 kinds of lookups now, quoted or unquoted */ quote= *p; - if(quote != '"') + if(quote != '"') /* " - this comment is hack for Aligorith's text editor's sanity */ quote= 0; if(quote==0) { diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index cddba59f979..5f532d7bb31 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -49,7 +49,6 @@ EnumPropertyItem actuator_type_items[] ={ {ACT_CAMERA, "CAMERA", 0, "Camera", ""}, {ACT_CONSTRAINT, "CONSTRAINT", 0, "Constraint", ""}, {ACT_EDIT_OBJECT, "EDIT_OBJECT", 0, "Edit Object", ""}, - {ACT_IPO, "FCURVE", 0, "F-Curve", ""}, {ACT_2DFILTER, "FILTER_2D", 0, "Filter 2D", ""}, {ACT_GAME, "GAME", 0, "Game", ""}, {ACT_MESSAGE, "MESSAGE", 0, "Message", ""}, @@ -77,8 +76,6 @@ static StructRNA* rna_Actuator_refine(struct PointerRNA *ptr) return &RNA_ActionActuator; case ACT_OBJECT: return &RNA_ObjectActuator; - case ACT_IPO: - return &RNA_FCurveActuator; case ACT_CAMERA: return &RNA_CameraActuator; case ACT_SOUND: @@ -353,6 +350,29 @@ static void rna_FcurveActuator_force_set(struct PointerRNA *ptr, int value) ia->flag &= ~ACT_IPOFORCE; } +static void rna_ActionActuator_add_set(struct PointerRNA *ptr, int value) +{ + bActuator *act = (bActuator *)ptr->data; + bActionActuator *aa = act->data; + + if(value == 1){ + aa->flag &= ~ACT_IPOFORCE; + aa->flag |= ACT_IPOADD; + }else + aa->flag &= ~ACT_IPOADD; +} + +static void rna_ActionActuator_force_set(struct PointerRNA *ptr, int value) +{ + bActuator *act = (bActuator *)ptr->data; + bActionActuator *aa = act->data; + + if(value == 1){ + aa->flag &= ~ACT_IPOADD; + aa->flag |= ACT_IPOFORCE; + }else + aa->flag &= ~ACT_IPOFORCE; +} static void rna_ObjectActuator_type_set(struct PointerRNA *ptr, int value) { @@ -426,15 +446,14 @@ EnumPropertyItem *rna_Actuator_type_itemf(bContext *C, PointerRNA *ptr, Property if (ob != NULL) { if (ob->type==OB_ARMATURE) { - RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ACTION); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ARMATURE); } } - + + RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ACTION); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CAMERA); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CONSTRAINT); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_EDIT_OBJECT); - RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_IPO); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_2DFILTER); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_GAME); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_MESSAGE); @@ -616,11 +635,39 @@ static void rna_def_action_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Priority", "Execution priority - lower numbers will override actions with higher numbers. With 2 or more actions at once, the overriding channels must be lower in the stack"); RNA_def_property_update(prop, NC_LOGIC, NULL); + prop= RNA_def_property(srna, "layer", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 4); /* This should match BL_ActionManager::MAX_ACTION_LAYERS */ + RNA_def_property_ui_text(prop, "Layer", "The animation layer to play the action on"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + prop= RNA_def_property(srna, "frame_property", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "frameProp"); RNA_def_property_ui_text(prop, "Frame Property", "Assign the action's current frame number to this property"); RNA_def_property_update(prop, NC_LOGIC, NULL); + /* booleans */ + prop= RNA_def_property(srna, "use_additive", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOADD); + RNA_def_property_boolean_funcs(prop, NULL, "rna_ActionActuator_add_set"); + RNA_def_property_ui_text(prop, "Add", "Action is added to the current loc/rot/scale in global or local coordinate according to Local flag"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop= RNA_def_property(srna, "use_force", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOFORCE); + RNA_def_property_boolean_funcs(prop, NULL, "rna_ActionActuator_force_set"); + RNA_def_property_ui_text(prop, "Force", "Apply Action as a global or local force depending on the local option (dynamic objects only)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop= RNA_def_property(srna, "use_local", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOLOCAL); + RNA_def_property_ui_text(prop, "L", "Let the Action act in local coordinates, used in Force and Add mode"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop= RNA_def_property(srna, "apply_to_children", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOCHILD); + RNA_def_property_ui_text(prop, "Child", "Update Action on all children Objects as well"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + #ifdef __NLA_ACTION_BY_MOTION_ACTUATOR prop= RNA_def_property(srna, "stride_length", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stridelength"); @@ -815,6 +862,7 @@ static void rna_def_object_actuator(BlenderRNA *brna) RNA_def_property_update(prop, NC_LOGIC, NULL); } +/* The fcurve actuator has been replace with the action actuator, so this is no longer used */ static void rna_def_fcurve_actuator(BlenderRNA *brna) { StructRNA *srna; @@ -1957,7 +2005,6 @@ void RNA_def_actuator(BlenderRNA *brna) rna_def_action_actuator(brna); rna_def_object_actuator(brna); - rna_def_fcurve_actuator(brna); rna_def_camera_actuator(brna); rna_def_sound_actuator(brna); rna_def_property_actuator(brna); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 7f817aa5b4b..d523a01dc2c 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -76,6 +76,10 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) ID *ownerId = (ID *)ptr->id.data; AnimData *adt = (AnimData *)ptr->data; + /* manage usercount for current action */ + if (adt->action) + id_us_min((ID*)adt->action); + /* assume that AnimData's action can in fact be edited... */ if ((value.data) && (ownerId)) { bAction *act = (bAction *)value.data; @@ -85,6 +89,7 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) if (ELEM(act->idroot, 0, GS(ownerId->name))) { /* can set */ adt->action = act; + id_us_plus((ID*)adt->action); } else { /* cannot set */ @@ -98,6 +103,7 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) act->id.name+2); adt->action = act; + id_us_plus((ID*)adt->action); } } else { diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 2060f75f9de..41d169a8870 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -814,6 +814,7 @@ static void rna_def_armature(BlenderRNA *brna) {ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"}, {ARM_B_BONE, "BBONE", 0, "B-Bone", "Display bones as boxes, showing subdivision and B-Splines"}, {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Display bones as extruded spheres, showing deformation influence volume"}, + {ARM_WIRE, "WIRE", 0, "Wire", "Display bones as thin wires, showing subdivision and B-Splines"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_ghost_type_items[] = { {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Frame", "Display Ghosts of poses within a fixed number of frames around the current frame"}, diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index a75ff601d08..4e178e77fd9 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -85,7 +85,7 @@ static EnumPropertyItem target_space_pchan_items[] = { static EnumPropertyItem owner_space_pchan_items[] = { {0, "WORLD", 0, "World Space", "The constraint is applied relative to the world coordinate system"}, {2, "POSE", 0, "Pose Space", "The constraint is applied in Pose Space, the object transformation is ignored"}, - {3, "LOCAL_WITH_PARENT", 0, "The constraint is applied relative to the local coordinate system of the object, with the parent transformation added"}, + {3, "LOCAL_WITH_PARENT", 0, "Local With Parent", "The constraint is applied relative to the local coordinate system of the object, with the parent transformation added"}, {1, "LOCAL", 0, "Local Space", "The constraint is applied relative to the local coordinate sytem of the object"}, {0, NULL, 0, NULL, NULL}}; @@ -1787,6 +1787,11 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna) RNA_def_property_enum_items(prop, constraint_distance_items); RNA_def_property_ui_text(prop, "Limit Mode", "Distances in relation to sphere of influence to allow"); RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); + + prop= RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMITDIST_TRANSFORM); + RNA_def_property_ui_text(prop, "For Transform", "Transforms are affected by this constraint as well"); + RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index a46f84a22d2..ab3665fb8ff 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -454,6 +454,30 @@ static void rna_FModifier_active_set(PointerRNA *ptr, int UNUSED(value)) fm->flag |= FMODIFIER_FLAG_ACTIVE; } +static void rna_FModifier_start_frame_range(PointerRNA *ptr, float *min, float *max) +{ + FModifier *fcm= (FModifier*)ptr->data; + + *min= MINAFRAMEF; + *max= (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)? fcm->efra : MAXFRAMEF; +} + +static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *max) +{ + FModifier *fcm= (FModifier*)ptr->data; + + *min= (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)? fcm->sfra : MINAFRAMEF; + *max= MAXFRAMEF; +} + +static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max) +{ + FModifier *fcm= (FModifier*)ptr->data; + + *min= 0.0f; + *max= fcm->efra - fcm->sfra; +} + static void rna_FModifier_active_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { FModifier *fm, *fmo= (FModifier*)ptr->data; @@ -1015,6 +1039,51 @@ static void rna_def_fmodifier(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, NULL, "rna_FModifier_active_set"); RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, "rna_FModifier_active_update"); RNA_def_property_ui_icon(prop, ICON_RADIOBUT_OFF, 1); + + /* restricted range */ + prop= RNA_def_property(srna, "use_restricted_range", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_RANGERESTRICT); + RNA_def_property_ui_text(prop, "Restrict Frame Range", "F-Curve Modifier is only applied for the specified frame range to help mask off effects in order to chain them"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); // XXX: depends on UI implementation + + prop= RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "sfra"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_start_frame_range"); + RNA_def_property_ui_text(prop, "Start Frame", "Frame that modifier's influence starts (if Restrict Frame Range is in use)"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + + prop= RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "efra"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_end_frame_range"); + RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if Restrict Frame Range is in use)"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + + prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "blendin"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range"); + RNA_def_property_ui_text(prop, "Blend In", "Number of frames from start frame for influence to take effect"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + + prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "blendout"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range"); + RNA_def_property_ui_text(prop, "Blend Out", "Number of frames from start frame for influence to fade out"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + + /* influence */ + prop= RNA_def_property(srna, "use_influence", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_USEINFLUENCE); + RNA_def_property_ui_text(prop, "Use Influence", "F-Curve Modifier's effects will be tempered by a default factor"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); + RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); // XXX: depends on UI implementation + + prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "influence"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Influence", "Amount of influence F-Curve Modifier will have when not fading in/out"); + RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); } /* *********************** */ @@ -1035,6 +1104,12 @@ static void rna_def_drivertarget(BlenderRNA *brna) {DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""}, {DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""}, {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem prop_local_space_items[] = { + {0, "WORLD_SPACE", 0, "World Space", "Transforms include effects of parenting/restpose and constraints"}, + {DTAR_FLAG_LOCALSPACE, "TRANSFORM_SPACE", 0, "Transform Space", "Transforms don't include parenting/restpose or constraints"}, + {DTAR_FLAG_LOCALSPACE|DTAR_FLAG_LOCAL_CONSTS, "LOCAL_SPACE", 0, "Local Space", "Transforms include effects of constraints but not parenting/restpose"}, + {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "DriverTarget", NULL); RNA_def_struct_ui_text(srna, "Driver Target", "Source of input values for driver variables"); @@ -1075,9 +1150,10 @@ static void rna_def_drivertarget(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Driver variable type"); RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data"); - prop= RNA_def_property(srna, "use_local_space_transform", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", DTAR_FLAG_LOCALSPACE); - RNA_def_property_ui_text(prop, "Local Space", "Use transforms in Local Space (as opposed to the worldspace default)"); + prop= RNA_def_property(srna, "transform_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, prop_local_space_items); + RNA_def_property_ui_text(prop, "Transform Space", "Space in which transforms are used"); RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data"); } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 8c4e4d9e736..eb2d38e9778 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -418,6 +418,8 @@ static StructRNA* rna_Sequence_refine(struct PointerRNA *ptr) return &RNA_ColorSequence; case SEQ_SPEED: return &RNA_SpeedControlSequence; + case SEQ_TITLECARD: + return &RNA_TitleCardSequence; default: return &RNA_Sequence; } @@ -886,6 +888,7 @@ static void rna_def_sequence(BlenderRNA *brna) {SEQ_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TITLECARD, "TITLE_CARD", 0, "Title Card", ""}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem blend_mode_items[]= { @@ -1666,6 +1669,37 @@ static void rna_def_speed_control(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); } +static void rna_def_title_card(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "TitleCardSequence", "EffectSequence"); + RNA_def_struct_ui_text(srna, "Title Card Sequence", "Sequence strip creating an image displaying some text on a plain color background"); + RNA_def_struct_sdna_from(srna, "TitleCardVars", "effectdata"); + + /* texts */ + prop= RNA_def_property(srna, "title", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "titlestr"); + RNA_def_property_ui_text(prop, "Title", "Text for main heading"); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); + + prop= RNA_def_property(srna, "subtitle", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Subtitle", "Additional text to be shown under the main heading"); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); + + /* colors */ + prop= RNA_def_property(srna, "color_background", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "bgcol"); + RNA_def_property_ui_text(prop, "Background Color", ""); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); + + prop= RNA_def_property(srna, "color_foreground", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "fgcol"); + RNA_def_property_ui_text(prop, "Text Color", ""); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); +} + void RNA_def_sequencer(BlenderRNA *brna) { rna_def_strip_element(brna); @@ -1691,6 +1725,7 @@ void RNA_def_sequencer(BlenderRNA *brna) rna_def_transform(brna); rna_def_solid_color(brna); rna_def_speed_control(brna); + rna_def_title_card(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 1bdb21d2d00..23060ba1aee 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -2902,7 +2902,11 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop= RNA_def_property(srna, "recent_files", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, 30); RNA_def_property_ui_text(prop, "Recent Files", "Maximum number of recently opened files to remember"); - + + prop= RNA_def_property(srna, "use_update_recent_files_on_load", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_NO_RECENTLOAD_UPDATE); + RNA_def_property_ui_text(prop, "Update Recent on Load", "When enabled, opening files will update the recent files list. Otherwise, updates only occur when saving"); + prop= RNA_def_property(srna, "use_save_preview_images", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SAVE_PREVIEWS); RNA_def_property_ui_text(prop, "Save Preview Images", "Enables automatic saving of preview images in the .blend file"); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index c088d0d2d43..79ec0360ac6 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -376,7 +376,12 @@ void WM_read_file(bContext *C, const char *filepath, ReportList *reports) if (retval != BKE_READ_FILE_FAIL) { G.relbase_valid = 1; - if(!G.background) /* assume automated tasks with background, dont write recent file list */ + + /* dont write recent file list if: + * 1) assuming automated tasks with background + * 2) user preference to not do this is enabled (i.e. developer testing mode) + */ + if (!G.background && !(U.flag & USER_NO_RECENTLOAD_UPDATE)) write_history(); } |