diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 996b033f3e9..b6e0aded1b8 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -133,7 +133,7 @@ struct bActionChannel *get_action_channel(struct bAction *act, const char *name struct bActionChannel *verify_action_channel(struct bAction *act, const char *name); /* exported for game engine */ -void blend_poses(struct bPose *dst, const struct bPose *src, float srcweight, short mode); +void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); /* map global time (frame nr) to strip converted time, doesn't clip */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 03f5a9903ef..3074656d761 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -357,7 +357,7 @@ bActionChannel *verify_action_channel(bAction *act, const char *name) /* Only allowed for Poses with identical channels */ -void blend_poses(bPose *dst, const bPose *src, float srcweight, short mode) +void blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { bPoseChannel *dchan; const bPoseChannel *schan; @@ -407,6 +407,8 @@ void blend_poses(bPose *dst, const bPose *src, float srcweight, short mode) dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; } } + + VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight); } @@ -504,6 +506,10 @@ static void rest_pose(bPose *pose) if (!pose) return; + pose->stride_offset[0]= 0.0f; + pose->stride_offset[1]= 0.0f; + pose->stride_offset[2]= 0.0f; + for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){ for (i=0; i<3; i++){ pchan->loc[i]=0.0; @@ -715,9 +721,12 @@ static float nla_time(float cfra, float unit) return cfra; } -static float stridechannel_frame(bAction *act, int stride_axis, char *name, float pdist) +static float stridechannel_frame(Object *ob, bActionStrip *strip, Path *path, float pathdist, float *stride_offset) { + bAction *act= strip->act; + char *name= strip->stridechannel; bActionChannel *achan= get_action_channel(act, name); + int stride_axis= strip->stride_axis; if(achan && achan->ipo) { IpoCurve *icu= NULL; @@ -745,29 +754,23 @@ static float stridechannel_frame(bAction *act, int stride_axis, char *name, floa if(foundvert && miny!=maxy) { float stridelen= fabs(maxy-miny), striptime; - float actiondist, step= 0.5, error, threshold=0.00001f*stridelen; - int max= 20; + float actiondist, pdist; + float vec1[4], vec2[4], dir[3]; /* amount path moves object */ - pdist = (float)fmod (pdist, stridelen); + pdist = (float)fmod (pathdist, stridelen); + striptime= pdist/stridelen; - /* wanted; the (0-1) factor that cancels out this distance, do simple newton-raphson */ - striptime= step; - do { - actiondist= eval_icu(icu, minx + striptime*(maxx-minx)) - miny; - - error= pdist - fabs(actiondist); - - step*=0.5f; - if(error > 0.0) - striptime += step; - else - striptime -= step; - - max--; - } - while( fabs(error) > threshold && max>0); + /* amount stride bone moves */ + actiondist= eval_icu(icu, minx + striptime*(maxx-minx)) - miny; + pdist = pdist - fabs(actiondist); + + /* now we need to go pdist further (or less) on cu path */ + where_on_path(ob, (pathdist)/path->totdist, vec1, dir); /* vec needs size 4 */ + where_on_path(ob, (pathdist+pdist)/path->totdist, vec2, dir); /* vec needs size 4 */ + VecSubf(stride_offset, vec1, vec2); + Mat4Mul3Vecfl(ob->obmat, stride_offset); return striptime; } } @@ -811,7 +814,7 @@ static void do_nla(Object *ob, int blocktype) rest_pose(tpose); /* Handle path */ - if (strip->flag & ACTSTRIP_USESTRIDE){ + if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){ if (ob->parent && ob->parent->type==OB_CURVE){ Curve *cu = ob->parent->data; float ctime, pdist; @@ -830,8 +833,9 @@ static void do_nla(Object *ob, int blocktype) } pdist = ctime*cu->path->totdist; - if(strip->stridechannel[0]) - striptime= stridechannel_frame(strip->act, strip->stride_axis, strip->stridechannel, pdist); + if(tpose && strip->stridechannel[0]) { + striptime= stridechannel_frame(ob->parent, strip, cu->path, pdist, tpose->stride_offset); + } else { if (strip->stridelen) { striptime = pdist / strip->stridelen; @@ -844,8 +848,9 @@ static void do_nla(Object *ob, int blocktype) frametime = (striptime * actlength) + strip->actstart; frametime= bsystem_time(ob, 0, frametime, 0.0); - if(blocktype==ID_AR) + if(blocktype==ID_AR) { extract_pose_from_action (tpose, strip->act, frametime); + } else if(blocktype==ID_OB) { extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); if(key) @@ -921,7 +926,12 @@ static void do_nla(Object *ob, int blocktype) if(blocktype==ID_OB) { execute_ipochannels(&chanbase); } - + else if(blocktype==ID_AR) { + /* apply stride offset to object */ + VecAddf(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset); + } + + /* free */ if (tpose){ free_pose_channels(tpose); MEM_freeN(tpose); @@ -929,7 +939,6 @@ static void do_nla(Object *ob, int blocktype) if(chanbase.first) BLI_freelistN(&chanbase); - } void do_all_pose_actions(Object *ob) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 8917178fea9..2b0920754cf 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1075,8 +1075,12 @@ void ob_parcurve(Object *ob, Object *par, float mat[][4]) SWAP(float, timeoffs, ob->sf); } + /* catch exceptions: feature for nla stride editing */ + if(ob->ipoflag & OB_DISABLE_PATH) { + ctime= 0.0f; + } /* catch exceptions: curve paths used as a duplicator */ - if(enable_cu_speed) { + else if(enable_cu_speed) { ctime= bsystem_time(ob, par, (float)G.scene->r.cfra, 0.0); if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 2f60045e9ea..db9926d4653 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -79,7 +79,8 @@ typedef struct bPoseChannel { typedef struct bPose{ ListBase chanbase; - int flag, pad; + int flag; + float stride_offset[3]; } bPose; typedef struct bActionChannel { diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 86bcbbf791a..4a9a4bf1784 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -282,6 +282,8 @@ extern Object workob; /* get ipo from from action or not? */ #define OB_ACTION_OB 256 #define OB_ACTION_KEY 512 + /* for stride edit */ +#define OB_DISABLE_PATH 1024 /* (short) trackflag / upflag */ #define OB_POSX 0 diff --git a/source/blender/src/drawnla.c b/source/blender/src/drawnla.c index 007238224de..2b0ba1a7ad3 100644 --- a/source/blender/src/drawnla.c +++ b/source/blender/src/drawnla.c @@ -398,15 +398,17 @@ static void draw_nla_strips_keys(SpaceNla *snla) #define B_NLA_LOCK 122 /* For now just returns the first selected strip */ -bActionStrip *get_active_nlastrip(void) +bActionStrip *get_active_nlastrip(Object **obpp) { Base *base; bActionStrip *strip; for (base=G.scene->base.first; base; base=base->next){ for (strip=base->object->nlastrips.first; strip; strip=strip->next){ - if (strip->flag & ACTSTRIP_SELECT) + if (strip->flag & ACTSTRIP_SELECT) { + *obpp= base->object; return strip; + } } } @@ -415,10 +417,11 @@ bActionStrip *get_active_nlastrip(void) void do_nlabuts(unsigned short event) { + Object *ob; bActionStrip *strip; /* Determine if an nla strip has been selected */ - strip = get_active_nlastrip(); + strip = get_active_nlastrip(&ob); if (!strip) return; switch(event) { @@ -427,8 +430,7 @@ void do_nlabuts(unsigned short event) allqueue(REDRAWNLA, 0); break; case B_NLA_PANEL: - - DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA); + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA); allqueue (REDRAWNLA, 0); allqueue (REDRAWVIEW3D, 0); break; @@ -443,6 +445,7 @@ void do_nlabuts(unsigned short event) static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES { + Object *ob; bActionStrip *strip; uiBlock *block; @@ -452,7 +455,7 @@ static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES if(uiNewPanel(curarea, block, "Transform Properties", "NLA", 10, 230, 318, 204)==0) return; /* Determine if an nla strip has been selected */ - strip = get_active_nlastrip(); + strip = get_active_nlastrip(&ob); if (!strip) return; /* first labels, for simpler align code :) */ @@ -488,8 +491,9 @@ static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES uiDefButS(block, TOG, B_NLA_PANEL, "Add", 230,60,75,19, &strip->mode, 0, 0, 0, 0, "Toggles additive blending mode"); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Use Path", 10,20,100,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride"); - uiDefButF(block, NUM, B_NLA_PANEL, "Stride:", 110,20,200,19, &strip->stridelen, 0.0001, 1000.0, 100, 0, "Distance covered by one complete cycle of the action specified in the Action Range"); + uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Stride Path", 10,20,100,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride"); + uiDefButBitS(block, TOG, OB_DISABLE_PATH, B_NLA_PANEL, "Disable Path", 110,20,100,19, &ob->ipoflag, 0, 0, 0, 0, "Plays action based on path position & stride"); + uiDefButF(block, NUM, B_NLA_PANEL, "Stride:", 210,20,100,19, &strip->stridelen, 0.0001, 1000.0, 100, 0, "Distance covered by one complete cycle of the action specified in the Action Range"); uiDefButS(block, ROW, B_NLA_PANEL, "X", 10, 0, 33, 19, &strip->stride_axis, 1, 0, 0, 0, "Dominant axis for Stride Bone"); uiDefButS(block, ROW, B_NLA_PANEL, "Y", 43, 0, 33, 19, &strip->stride_axis, 1, 1, 0, 0, "Dominant axis for Stride Bone");