diff options
-rw-r--r-- | source/blender/blenkernel/BKE_lattice.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/action.c | 308 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 37 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lattice.c | 89 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/nla.c | 16 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 7 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 17 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 7 | ||||
-rw-r--r-- | source/blender/include/BIF_editnla.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_action_types.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_nla_types.h | 25 | ||||
-rw-r--r-- | source/blender/src/drawnla.c | 135 | ||||
-rw-r--r-- | source/blender/src/editnla.c | 40 |
14 files changed, 581 insertions, 123 deletions
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 6e738bd53fb..bcf65fcd540 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -53,7 +53,12 @@ void calc_latt_deform(float *co, float weight); void end_latt_deform(void); int object_deform_mball(struct Object *ob); void outside_lattice(struct Lattice *lt); -void curve_deform_verts(struct Object *cuOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis); +void curve_deform_verts(struct Object *cuOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, char *vgroup, short defaxis); +void curve_deform_vector(struct Object *cuOb, struct Object *target, + float *orco, float *vec, float mat[][3], int no_rot_axis); + void lattice_deform_verts(struct Object *laOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 08462472406..6d0a5f672cc 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -57,6 +57,7 @@ #include "BKE_global.h" #include "BKE_ipo.h" #include "BKE_key.h" +#include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" @@ -386,6 +387,68 @@ bActionChannel *verify_action_channel(bAction *act, const char *name) return chan; } +/* ************** time ****************** */ + +static bActionStrip *get_active_strip(Object *ob) +{ + bActionStrip *strip; + + if(ob->action==NULL) + return NULL; + + for (strip=ob->nlastrips.first; strip; strip=strip->next) + if(strip->flag & ACTSTRIP_ACTIVE) + break; + + if(strip && strip->act==ob->action) + return strip; + return NULL; +} + +/* non clipped mapping of strip */ +static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert) +{ + float length, actlength, repeat; + + if (strip->flag & ACTSTRIP_USESTRIDE) + repeat= 1.0f; + else + repeat= strip->repeat; + + length = strip->end-strip->start; + if(length==0.0f) + length= 1.0f; + actlength = strip->actend-strip->actstart; + + + + if(invert) + return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; + else + return repeat*actlength*(cframe - strip->start)/length + strip->actstart; +} + +/* if the conditions match, it converts current time to strip time */ +float get_action_frame(Object *ob, float cframe) +{ + bActionStrip *strip= get_active_strip(ob); + + if(strip) + return get_actionstrip_frame(strip, cframe, 0); + return cframe; +} + +/* inverted, strip time to current time */ +float get_action_frame_inv(Object *ob, float cframe) +{ + bActionStrip *strip= get_active_strip(ob); + + if(strip) + return get_actionstrip_frame(strip, cframe, 1); + return cframe; +} + + /* ************************ Blending with NLA *************** */ static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mode) @@ -406,6 +469,87 @@ static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mo VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight); } + +/* + +bone matching diagram, strips A and B + + .------------------------. + | A | + '------------------------' + . . b2 + . .-------------v----------. + . | B . | + . '------------------------' + . . . + . . . +offset: . 0 . A-B . A-b2+B + . . . + +*/ + + +static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, float srcweight, short mode) +{ + /* matching offset bones */ + /* take dst offset, and put src on on that location */ + + if(strip->offs_bone[0]==0) + return; + + /* are we also blending with matching bones? */ + if(strip->prev && strip->start>=strip->prev->start) { + bPoseChannel *dpchan= get_pose_channel(dst, strip->offs_bone); + if(dpchan) { + bPoseChannel *spchan= get_pose_channel(src, strip->offs_bone); + if(spchan) { + float vec[3]; + + /* dst->ctime has the internal strip->prev action time */ + /* map this time to nla time */ + + float ctime= get_actionstrip_frame(strip, src->ctime, 1); + + if( ctime > strip->prev->end) { + bActionChannel *achan; + + /* add src to dest, minus the position of src on strip->prev->end */ + + ctime= get_actionstrip_frame(strip, strip->prev->end, 0); + + achan= get_action_channel(strip->act, strip->offs_bone); + if(achan && achan->ipo) { + bPoseChannel pchan; + /* Evaluates and sets the internal ipo value */ + calc_ipo(achan->ipo, ctime); + /* This call also sets the pchan flags */ + execute_action_ipo(achan, &pchan); + + /* store offset that moves src to location of pchan */ + VecSubf(vec, dpchan->loc, pchan.loc); + + Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec); + } + } + else { + /* store offset that moves src to location of dst */ + + VecSubf(vec, dpchan->loc, spchan->loc); + Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec); + } + + /* if blending, we only add with factor scrweight */ + VecMulf(vec, srcweight); + + VecAddf(dst->cyclic_offset, dst->cyclic_offset, vec); + } + } + } + + VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset); +} + + /* Only allowed for Poses with identical channels */ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { @@ -457,6 +601,9 @@ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode) dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; } } + + /* this pose is now in src time */ + dst->ctime= src->ctime; } @@ -545,6 +692,8 @@ void extract_pose_from_action(bPose *pose, bAction *act, float ctime) do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime); } } + + pose->ctime= ctime; /* used for cyclic offset matching */ } /* for do_all_pose_actions, clears the pose */ @@ -556,17 +705,16 @@ 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; + memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); + memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); - for (pchan=pose->chanbase.first; pchan; pchan=pchan->next){ - for (i=0; i<3; i++){ - pchan->loc[i]=0.0; - pchan->quat[i+1]=0.0; - pchan->size[i]=1.0; + for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){ + for (i=0; i<3; i++) { + pchan->loc[i]= 0.0f; + pchan->quat[i+1]= 0.0f; + pchan->size[i]= 1.0f; } - pchan->quat[0]=1.0; + pchan->quat[0]= 1.0f; pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); } @@ -685,69 +833,7 @@ static void execute_ipochannels(ListBase *lb) } } - -/* ************** time ****************** */ - -static bActionStrip *get_active_strip(Object *ob) -{ - bActionStrip *strip; - - if(ob->action==NULL) - return NULL; - - for (strip=ob->nlastrips.first; strip; strip=strip->next) - if(strip->flag & ACTSTRIP_ACTIVE) - break; - - if(strip && strip->act==ob->action) - return strip; - return NULL; -} - -/* non clipped mapping of strip */ -static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert) -{ - float length, actlength, repeat; - - if (strip->flag & ACTSTRIP_USESTRIDE) - repeat= 1.0f; - else - repeat= strip->repeat; - - length = strip->end-strip->start; - if(length==0.0f) - length= 1.0f; - actlength = strip->actend-strip->actstart; - - - - if(invert) - return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; - else - return repeat*actlength*(cframe - strip->start)/length + strip->actstart; -} - -/* if the conditions match, it converts current time to strip time */ -float get_action_frame(Object *ob, float cframe) -{ - bActionStrip *strip= get_active_strip(ob); - - if(strip) - return get_actionstrip_frame(strip, cframe, 0); - return cframe; -} - -/* inverted, strip time to current time */ -float get_action_frame_inv(Object *ob, float cframe) -{ - bActionStrip *strip= get_active_strip(ob); - - if(strip) - return get_actionstrip_frame(strip, cframe, 1); - return cframe; -} - - +/* nla timing */ /* this now only used for repeating cycles, to enable fields and blur. */ /* the whole time control in blender needs serious thinking... */ @@ -840,6 +926,54 @@ static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip return 0.0f; } +static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float time) +{ + + if(time > 1.0f) { + bActionChannel *achan= get_action_channel(strip->act, strip->offs_bone); + + if(achan && achan->ipo) { + IpoCurve *icu= NULL; + Bone *bone; + float min[3]={0.0f, 0.0f, 0.0f}, max[3]={0.0f, 0.0f, 0.0f}; + int index=0, foundvert= 0; + + /* calculate the min/max */ + for (icu=achan->ipo->curve.first; icu; icu=icu->next) { + if(icu->totvert>1) { + + if(icu->adrcode==AC_LOC_X) + index= 0; + else if(icu->adrcode==AC_LOC_Y) + index= 1; + else if(icu->adrcode==AC_LOC_Z) + index= 2; + else + continue; + + foundvert= 1; + min[index]= icu->bezt[0].vec[1][1]; + max[index]= icu->bezt[icu->totvert-1].vec[1][1]; + } + } + if(foundvert) { + /* bring it into armature space */ + VecSubf(min, max, min); + bone= get_named_bone(ob->data, strip->offs_bone); /* weak */ + Mat4Mul3Vecfl(bone->arm_mat, min); + + /* dominant motion, cyclic_offset was cleared in rest_pose */ + if( fabs(min[0]) >= fabs(min[1]) && fabs(min[0]) >= fabs(min[2])) + pose->cyclic_offset[0]= time*min[0]; + else if( fabs(min[1]) >= fabs(min[0]) && fabs(min[1]) >= fabs(min[2])) + pose->cyclic_offset[1]= time*min[1]; + else + pose->cyclic_offset[2]= time*min[2]; + } + } + } +} + /* simple case for now; only the curve path with constraint value > 0.5 */ /* blending we might do later... */ static Object *get_parent_path(Object *ob) @@ -917,7 +1051,7 @@ static void do_nla(Object *ob, int blocktype) actlength = strip->actend-strip->actstart; striptime = (scene_cfra-(strip->start)) / length; stripframe = (scene_cfra-(strip->start)) ; - + if (striptime>=0.0){ if(blocktype==ID_AR) @@ -982,25 +1116,32 @@ static void do_nla(Object *ob, int blocktype) /* Mod to repeat */ if(strip->repeat!=1.0f) { - striptime*= strip->repeat; - striptime = (float)fmod (striptime, 1.0f + 0.1f/length); + float cycle= striptime*strip->repeat; + + striptime = (float)fmod (cycle, 1.0f + 0.1f/length); + cycle-= striptime; + + if(blocktype==ID_AR) + cyclic_offs_bone(ob, tpose, strip, cycle); } frametime = (striptime * actlength) + strip->actstart; frametime= nla_time(frametime, (float)strip->repeat); - 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) extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); - } + } + doit=1; } } /* Handle extend */ - else{ + else { if (strip->flag & ACTSTRIP_HOLDLASTFRAME){ /* we want the strip to hold on the exact fraction of the repeat value */ @@ -1015,6 +1156,13 @@ static void do_nla(Object *ob, int blocktype) if(key) extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); } + + /* handle cycle hold */ + if(strip->repeat!=1.0f) { + if(blocktype==ID_AR) + cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f); + } + doit=1; } } @@ -1033,6 +1181,9 @@ static void do_nla(Object *ob, int blocktype) blendfac = 1; if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */ + /* offset bone, for matching cycles */ + blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode); + blend_poses (ob->pose, tpose, blendfac, strip->mode); if(dostride) blend_pose_strides (ob->pose, tpose, blendfac, strip->mode); @@ -1061,7 +1212,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/armature.c b/source/blender/blenkernel/intern/armature.c index aaa8e638ec9..fe703007e50 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -43,6 +43,7 @@ #include "DNA_mesh_types.h" #include "DNA_lattice_types.h" #include "DNA_meshdata_types.h" +#include "DNA_nla_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_view3d_types.h" @@ -58,6 +59,7 @@ #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_object.h" @@ -1592,6 +1594,35 @@ static void do_local_constraint(bPoseChannel *pchan, bConstraint *con) } } +static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) +{ + bActionModifier *amod; + bActionStrip *strip; + float scene_cfra= G.scene->r.cfra; + + for (strip=armob->nlastrips.first; strip; strip=strip->next) { + if(scene_cfra>=strip->start && scene_cfra<=strip->end) { + + for(amod= strip->modifiers.first; amod; amod= amod->next) { + if(amod->type==ACTSTRIP_MOD_DEFORM) { + /* validate first */ + if(amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) { + + if( strcmp(pchan->name, amod->channel)==0 ) { + float mat4[4][4], mat3[3][3]; + + curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis); + Mat4CpyMat4(mat4, pchan->pose_mat); + Mat4MulMat34(pchan->pose_mat, mat3, mat4); + + } + } + } + } + } + } +} + /* The main armature solver, does all constraints excluding IK */ /* pchan is validated, as having bone and parent pointer */ @@ -1657,9 +1688,13 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) else Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL); } - else + else { Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat); + /* only rootbones get the cyclic offset */ + VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset); + } + do_strip_modifiers(ob, bone, pchan); /* Do constraints */ if(pchan->constraints.first) { diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 5847b913004..c65e9363274 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -389,7 +389,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int } } - /* driver dependencies */ + /* driver dependencies, nla modifiers */ if(ob->ipo) dag_add_driver_relation(ob->ipo, dag, node, 0); @@ -416,6 +416,15 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int for (chan = strip->act->chanbase.first; chan; chan=chan->next) if(chan->ipo) dag_add_driver_relation(chan->ipo, dag, node, 1); + if(strip->modifiers.first) { + bActionModifier *amod; + for(amod= strip->modifiers.first; amod; amod= amod->next) { + if(amod->ob) { + node2 = dag_get_node(dag, amod->ob); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + } + } + } } } if (ob->modifiers.first) { diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 3d8fd7d1311..d751169d115 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -450,19 +450,25 @@ void end_latt_deform() */ typedef struct { float dmin[3], dmax[3], dsize, dloc[3]; - float curvespace[4][4], objectspace[4][4]; + float curvespace[4][4], objectspace[4][4], objectspace3[3][3]; + int no_rot_axis; } CurveDeform; -static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) +static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd, int dloc) { Mat4Invert(ob->imat, ob->obmat); Mat4MulMat4(cd->objectspace, par->obmat, ob->imat); Mat4Invert(cd->curvespace, cd->objectspace); - + Mat3CpyMat4(cd->objectspace3, cd->objectspace); + // offset vector for 'no smear' - Mat4Invert(par->imat, par->obmat); - VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]); - + if(dloc) { + Mat4Invert(par->imat, par->obmat); + VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]); + } + else cd->dloc[0]=cd->dloc[1]=cd->dloc[2]= 0.0f; + + cd->no_rot_axis= 0; } /* this makes sure we can extend for non-cyclic. *vec needs 4 items! */ @@ -508,10 +514,12 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* for each point, rotate & translate to curve */ /* use path, since it has constant distances */ /* co: local coord, result local too */ -static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd) + /* returns quaternion for rotation, using cd->no_rot_axis */ + /* axis is using another define!!! */ +static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd) { Curve *cu= par->data; - float fac, loc[4], dir[3], *quat, q[4], mat[3][3], cent[3]; + float fac, loc[4], dir[3], cent[3]; short upflag, index; if(axis==MOD_CURVE_POSX || axis==MOD_CURVE_NEGX) { @@ -538,17 +546,33 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c /* to be sure, mostly after file load */ if(cu->path==NULL) { makeDispListCurveTypes(par, 0); - if(cu->path==NULL) return; // happens on append... + if(cu->path==NULL) return NULL; // happens on append... } + /* options */ - if(cu->flag & CU_STRETCH) - fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]); - else - fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); + if(ELEM3(axis, OB_NEGX, OB_NEGY, OB_NEGZ)) { + if(cu->flag & CU_STRETCH) + fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]); + else + fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist); + } + else { + if(cu->flag & CU_STRETCH) + fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]); + else + fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); + } + if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */ - - quat= vectoquat(dir, axis-1, upflag); /* -1 for compatibility with old track defines */ + float q[4], mat[3][3]; + float *quat; + + if(cd->no_rot_axis) /* set by caller */ + dir[cd->no_rot_axis-1]= 0.0f; + + /* -1 for compatibility with old track defines */ + quat= vectoquat(dir, axis-1, upflag); /* gives static quat */ /* the tilt */ if(loc[3]!=0.0) { @@ -568,8 +592,9 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c /* translation */ VECADD(co, cent, loc); + return quat; } - + return NULL; } void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) @@ -581,7 +606,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist - init_curve_deform(cuOb, target, &cd); + init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0); /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with @@ -658,6 +683,36 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v cu->flag = flag; } +/* input vec and orco = local coord in armature space */ +/* orco is original not-animated or deformed reference point */ +/* result written in vec and mat */ +void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis) +{ + CurveDeform cd; + float *quat; + + init_curve_deform(cuOb, target, &cd, 0); /* 0 no dloc */ + cd.no_rot_axis= no_rot_axis; /* option to only rotate for XY, for example */ + + VECCOPY(cd.dmin, orco); + VECCOPY(cd.dmax, orco); + + Mat4MulVecfl(cd.curvespace, vec); + + quat= calc_curve_deform(cuOb, vec, target->trackflag+1, &cd); + if(quat) { + float qmat[3][3]; + + QuatToMat3(quat, qmat); + Mat3MulMat3(mat, qmat, cd.objectspace3); + } + else + Mat3One(mat); + + Mat4MulVecfl(cd.objectspace, vec); + +} + void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup) { diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index a8f1f2406f1..a348aef0399 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -74,6 +74,11 @@ void copy_actionstrip (bActionStrip **dst, bActionStrip **src){ if (dstrip->ipo) dstrip->ipo->id.us++; + + if (dstrip->modifiers.first) { + duplicatelist (&dstrip->modifiers, &sstrip->modifiers); + } + } void copy_nlastrips (ListBase *dst, ListBase *src) @@ -93,6 +98,11 @@ void copy_nlastrips (ListBase *dst, ListBase *src) strip->act->id.us++; if (strip->ipo) strip->ipo->id.us++; + if (strip->modifiers.first) { + ListBase listb; + duplicatelist (&listb, &strip->modifiers); + strip->modifiers= listb; + } } } @@ -139,7 +149,7 @@ bActionStrip *convert_action_to_strip (Object *ob) } - +/* not strip itself! */ void free_actionstrip(bActionStrip* strip) { if (!strip) @@ -153,6 +163,10 @@ void free_actionstrip(bActionStrip* strip) strip->ipo->id.us--; strip->ipo = NULL; } + if (strip->modifiers.first) { + BLI_freelistN(&strip->modifiers); + } + } void free_nlastrips (ListBase *nlalist) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index fd0bd47430e..a7404fa8f51 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -333,6 +333,13 @@ void unlink_object(Object *ob) for(strip= ob->nlastrips.first; strip; strip= strip->next) { if(strip->object==ob) strip->object= NULL; + + if(strip->modifiers.first) { + bActionModifier *amod; + for(amod= strip->modifiers.first; amod; amod= amod->next) + if(amod->ob==ob) + amod->ob= NULL; + } } } obt= obt->id.next; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e66a888aa47..99b778b549e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1390,11 +1390,14 @@ static void direct_link_scriptlink(FileData *fd, ScriptLink *slink) static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist) { bActionStrip *strip; - + bActionModifier *amod; + for (strip=striplist->first; strip; strip=strip->next){ strip->object = newlibadr(fd, id->lib, strip->object); strip->act = newlibadr_us(fd, id->lib, strip->act); strip->ipo = newlibadr(fd, id->lib, strip->ipo); + for(amod= strip->modifiers.first; amod; amod= amod->next) + amod->ob= newlibadr(fd, id->lib, amod->ob); } } @@ -2502,6 +2505,16 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) } } +static void direct_link_nlastrips(FileData *fd, ListBase *strips) +{ + bActionStrip *strip; + + link_list(fd, strips); + + for(strip= strips->first; strip; strip= strip->next) + link_list(fd, &strip->modifiers); +} + static void direct_link_object(FileData *fd, Object *ob) { PartEff *paf; @@ -2520,7 +2533,7 @@ static void direct_link_object(FileData *fd, Object *ob) direct_link_pose(fd, ob->pose); link_list(fd, &ob->defbase); - link_list(fd, &ob->nlastrips); + direct_link_nlastrips(fd, &ob->nlastrips); link_list(fd, &ob->constraintChannels); direct_link_scriptlink(fd, &ob->scriptlink); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 96c1b2ceb9b..3955530b3b3 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -632,9 +632,14 @@ static void write_actuators(WriteData *wd, ListBase *lb) static void write_nlastrips(WriteData *wd, ListBase *nlabase) { bActionStrip *strip; - + bActionModifier *amod; + for (strip=nlabase->first; strip; strip=strip->next) writestruct(wd, DATA, "bActionStrip", 1, strip); + for (strip=nlabase->first; strip; strip=strip->next) { + for(amod= strip->modifiers.first; amod; amod= amod->next) + writestruct(wd, DATA, "bActionModifier", 1, amod); + } } static void write_constraints(WriteData *wd, ListBase *conlist) diff --git a/source/blender/include/BIF_editnla.h b/source/blender/include/BIF_editnla.h index f4fa4629d9f..fafc95fb03f 100644 --- a/source/blender/include/BIF_editnla.h +++ b/source/blender/include/BIF_editnla.h @@ -54,6 +54,7 @@ void reset_action_strips(int val); void synchronize_action_strips(void); void snap_action_strips(void); void add_nlablock(void); +void copy_action_modifiers(void); /* Baking */ void bake_all_to_action(void); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index e688b778894..2c6122198b8 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -83,7 +83,9 @@ typedef struct bPoseChannel { typedef struct bPose{ ListBase chanbase; int flag; - float stride_offset[3]; + float ctime; /* local action time of this pose */ + float stride_offset[3]; /* applied to object */ + float cyclic_offset[3]; /* result of match and cycles, applied in where_is_pose() */ } bPose; typedef struct bActionChannel { diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h index fe01fa91eb2..c97ef5ab197 100644 --- a/source/blender/makesdna/DNA_nla_types.h +++ b/source/blender/makesdna/DNA_nla_types.h @@ -33,14 +33,33 @@ #ifndef DNA_NLA_TYPES_H #define DNA_NLA_TYPES_H +#include "DNA_listBase.h" + struct bAction; struct Ipo; struct Object; +/* simple uniform modifier structure, assumed it can hold all type info */ +typedef struct bActionModifier { + struct bActionModifier *next, *prev; + short type, flag; + char channel[32]; + + /* path deform modifier */ + short pad, no_rot_axis; + struct Object *ob; + +} bActionModifier; + +#define ACTSTRIP_MOD_DEFORM 0 +#define ACTSTRIP_MOD_NOISE 1 +#define ACTSTRIP_MOD_OOMPH 2 + typedef struct bActionStrip { struct bActionStrip *next, *prev; short flag, mode; - short stride_axis, pad; /* axis 0=x, 1=y, 2=z */ + short stride_axis; /* axis 0=x, 1=y, 2=z */ + short curmod; /* current modifier for buttons */ struct Ipo *ipo; /* Blending ipo */ struct bAction *act; /* The action referenced by this strip */ @@ -54,6 +73,10 @@ typedef struct bActionStrip { float blendin, blendout; char stridechannel[32]; /* Instead of stridelen, it uses an action channel */ + char offs_bone[32]; /* if repeat, use this bone/channel for defining offset */ + + struct ListBase modifiers; /* modifier stack */ + } bActionStrip; #define ACTSTRIPMODE_BLEND 0 diff --git a/source/blender/src/drawnla.c b/source/blender/src/drawnla.c index 9c66eae794b..a1a5bebe8d6 100644 --- a/source/blender/src/drawnla.c +++ b/source/blender/src/drawnla.c @@ -41,6 +41,7 @@ #include "BMF_Api.h" #include <stdlib.h> +#include <string.h> #include <stdio.h> #include "DNA_view3d_types.h" @@ -183,7 +184,13 @@ static void draw_nla_channels(void) BIF_icon_draw(x+16, y-8, ICON_DOT); glDisable(GL_BLEND); } + if(strip->modifiers.first) { + glEnable(GL_BLEND); + BIF_icon_draw(x+34, y-8, ICON_MODIFIER); + glDisable(GL_BLEND); + } } + y-=(NLACHANNELHEIGHT+NLACHANNELSKIP); } } @@ -398,6 +405,11 @@ static void draw_nla_strips_keys(SpaceNla *snla) #define B_NLA_PANEL 121 #define B_NLA_LOCK 122 +#define B_NLA_MOD_ADD 123 +#define B_NLA_MOD_NEXT 124 +#define B_NLA_MOD_PREV 125 +#define B_NLA_MOD_DEL 126 +#define B_NLA_MOD_DEPS 127 /* For now just returns the first selected strip */ bActionStrip *get_active_nlastrip(Object **obpp) @@ -442,19 +454,73 @@ void do_nlabuts(unsigned short event) allqueue (REDRAWACTION, 0); allqueue (REDRAWVIEW3D, 0); break; + + case B_NLA_MOD_ADD: + { + bActionModifier *amod= MEM_callocN(sizeof(bActionModifier), "bActionModifier"); + + BLI_addtail(&strip->modifiers, amod); + strip->curmod= BLI_countlist(&strip->modifiers)-1; + allqueue (REDRAWNLA, 0); + } + break; + case B_NLA_MOD_DEL: + if(strip->modifiers.first) { + bActionModifier *amod= BLI_findlink(&strip->modifiers, strip->curmod); + BLI_remlink(&strip->modifiers, amod); + MEM_freeN(amod); + if(strip->curmod) strip->curmod--; + allqueue (REDRAWNLA, 0); + } + break; + case B_NLA_MOD_NEXT: + if(strip->curmod < BLI_countlist(&strip->modifiers)-1) + strip->curmod++; + allqueue (REDRAWNLA, 0); + break; + case B_NLA_MOD_PREV: + if(strip->curmod > 0) + strip->curmod--; + allqueue (REDRAWNLA, 0); + break; + case B_NLA_MOD_DEPS: + DAG_scene_sort(G.scene); + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA); + break; } } +static char *make_modifier_menu(ListBase *lb) +{ + bActionModifier *amod; + int index= 1; + char *str, item[64], *types[3]={"Deform", "Noise", "Oomph"}; + + for (amod = lb->first; amod; amod=amod->next, index++); + str= MEM_mallocN(index*64, "key string"); + str[0]= 0; + + index= 0; + for (amod = lb->first; amod; amod=amod->next, index++) { + sprintf (item, "|%s %s%%x%d", types[amod->type], amod->channel, index); + strcat(str, item); + } + + return str; +} + + static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES { Object *ob; bActionStrip *strip; uiBlock *block; + uiBut *but; block= uiNewBlock(&curarea->uiblocks, "nla_panel_properties", UI_EMBOSS, UI_HELV, curarea->win); uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl); uiSetPanelHandler(NLA_HANDLER_PROPERTIES); // for close and esc - if(uiNewPanel(curarea, block, "Transform Properties", "NLA", 10, 230, 318, 204)==0) return; + if(uiNewPanel(curarea, block, "Transform Properties", "NLA", 10, 230, 318, 224)==0) return; /* Determine if an nla strip has been selected */ strip = get_active_nlastrip(&ob); @@ -488,26 +554,61 @@ static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES uiBlockBeginAlign(block); uiDefButF(block, NUM, B_NLA_PANEL, "Repeat:", 160,100,150,19, &strip->repeat, 0.001, 1000.0f, 100, 0, "Number of times the action should repeat"); - uiDefButBitS(block, TOG, ACTSTRIP_HOLDLASTFRAME, B_NLA_PANEL, "Hold", 160,80,75,19, &strip->flag, 0, 0, 0, 0, "Toggles whether to continue displaying the last frame past the end of the strip"); - uiDefButS(block, TOG, B_NLA_PANEL, "Add", 235,80,75,19, &strip->mode, 0, 0, 0, 0, "Toggles additive blending mode"); + but= uiDefButC(block, TEX, B_NLA_PANEL, "OffsBone:", 160,80,150,19, strip->offs_bone, 0, 31.0f, 0, 0, "Name of Bone that defines offset for repeat"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); + uiDefButBitS(block, TOG, ACTSTRIP_HOLDLASTFRAME, B_NLA_PANEL, "Hold", 160,60,75,19, &strip->flag, 0, 0, 0, 0, "Toggles whether to continue displaying the last frame past the end of the strip"); + uiDefButS(block, TOG, B_NLA_PANEL, "Add", 235,60,75,19, &strip->mode, 0, 0, 0, 0, "Toggles additive blending mode"); uiBlockEndAlign(block); - uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Stride Path", 10, 50,140,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride"); - if(ob->dup_group) - uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_NLA_PANEL, "Target:", 160,50, 150, 19, &strip->object, "Target Object in this group"); - - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, OB_DISABLE_PATH, B_NLA_PANEL, "Disable", 10,20,60,19, &ob->ipoflag, 0, 0, 0, 0, "Disable path temporally, for editing cycles"); - - uiDefButF(block, NUM, B_NLA_PANEL, "Offs:", 70,20,120,19, &strip->actoffs, -500, 500.0, 100, 0, "Action offset in frames to tweak cycle of the action within the stride"); - uiDefButF(block, NUM, B_NLA_PANEL, "Stri:", 190,20,120,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, 30,140,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride"); - 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"); - uiDefButS(block, ROW, B_NLA_PANEL, "Z", 76, 0, 34, 19, &strip->stride_axis, 1, 2, 0, 0, "Dominant axis for Stride Bone"); + if(ob->dup_group) + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_NLA_PANEL, "Target:", 160,30, 150, 19, &strip->object, "Target Object in this group"); - uiDefBut(block, TEX, B_NLA_PANEL, "Stride Bone:", 110, 0, 200, 19, strip->stridechannel, 1, 31, 0, 0, "Name of Bone used for stride"); - + if(strip->flag & ACTSTRIP_USESTRIDE) { + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, OB_DISABLE_PATH, B_NLA_PANEL, "Disable", 10,0,60,19, &ob->ipoflag, 0, 0, 0, 0, "Disable path temporally, for editing cycles"); + + uiDefButF(block, NUM, B_NLA_PANEL, "Offs:", 70,0,120,19, &strip->actoffs, -500, 500.0, 100, 0, "Action offset in frames to tweak cycle of the action within the stride"); + uiDefButF(block, NUM, B_NLA_PANEL, "Stri:", 190,0,120,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, -20, 33, 19, &strip->stride_axis, 1, 0, 0, 0, "Dominant axis for Stride Bone"); + uiDefButS(block, ROW, B_NLA_PANEL, "Y", 43, -20, 33, 19, &strip->stride_axis, 1, 1, 0, 0, "Dominant axis for Stride Bone"); + uiDefButS(block, ROW, B_NLA_PANEL, "Z", 76, -20, 34, 19, &strip->stride_axis, 1, 2, 0, 0, "Dominant axis for Stride Bone"); + + but= uiDefBut(block, TEX, B_NLA_PANEL, "Stride Bone:", 110, -20, 200, 19, strip->stridechannel, 1, 31, 0, 0, "Name of Bone used for stride"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); + } + else { /* modifiers */ + bActionModifier *amod= BLI_findlink(&strip->modifiers, strip->curmod); + + uiBlockBeginAlign(block); + uiDefBut(block, BUT, B_NLA_MOD_ADD, "Add Modifier", 10,0,140,19, NULL, 0, 0, 0, 0, ""); + if(amod) { + char *strp= make_modifier_menu(&strip->modifiers); + + uiDefIconBut(block, BUT, B_NLA_MOD_NEXT, ICON_TRIA_LEFT, 150,0,20,19, NULL, 0, 0, 0, 0, "Previous Modifier"); + uiDefButS(block, MENU, B_NLA_PANEL, strp, 170,0,20,19, &strip->curmod, 0, 0, 0, 0, "Browse modifier"); + MEM_freeN(strp); + uiDefIconBut(block, BUT, B_NLA_MOD_PREV, ICON_TRIA_RIGHT, 190,0,20,19, NULL, 0, 0, 0, 0, "Next Modifier"); + uiDefButS(block, MENU, B_REDR, "Deform %x0|Noise %x1|Oomph %x2", 210,0,80,19, &amod->type, 0, 0, 0, 0, "Modifier type"); + uiDefIconBut(block, BUT, B_NLA_MOD_DEL, ICON_X, 290,0,20,19, NULL, 0, 0, 0, 0, "Delete Modifier"); + + if(amod->type==ACTSTRIP_MOD_DEFORM) { + but= uiDefBut(block, TEX, B_NLA_PANEL, "Chan:", 10, -20, 130, 19, amod->channel, 1, 31, 0, 0, "Name of channel used for modifier"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob); + uiDefButS(block, MENU, B_REDR, "All%x0|XY%x3|XZ%x2|YZ%x1", 140,-20,40,19, &amod->no_rot_axis, 0, 0, 0, 0, "Enable rotation axes (local for curve)"); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_NLA_MOD_DEPS, "Ob:", 180,-20, 130, 19, &amod->ob, "Curve Object"); + } + else + uiDefBut(block, LABEL, B_NOP, "Ack! Not implemented.", 10, -20, 150, 19, NULL, 0, 0, 0, 0, ""); + + } + else { /* for panel aligning */ + uiBlockEndAlign(block); + uiDefBut(block, LABEL, B_NOP, " ", 10, -20, 150, 19, NULL, 0, 0, 0, 0, ""); + } + } } static void nla_blockhandlers(ScrArea *sa) diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c index ac415cbed53..6bb42502f5a 100644 --- a/source/blender/src/editnla.c +++ b/source/blender/src/editnla.c @@ -54,6 +54,7 @@ #include "DNA_userdef_types.h" #include "BKE_action.h" +#include "BKE_blender.h" #include "BKE_depsgraph.h" #include "BKE_group.h" #include "BKE_global.h" @@ -1647,7 +1648,11 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt) break; case CKEY: - convert_nla(mval); + if(G.qual==LR_CTRLKEY) { + if(okee("Copy Modifiers")) + copy_action_modifiers(); + } + else convert_nla(mval); break; case DKEY: @@ -1848,3 +1853,36 @@ void bake_all_to_action(void) } } } + +void copy_action_modifiers(void) +{ + bActionStrip *strip, *actstrip; + Object *ob= OBACT; + + if(ob==NULL) + return; + + /* active strip */ + for (actstrip=ob->nlastrips.first; actstrip; actstrip=actstrip->next) + if(actstrip->flag & ACTSTRIP_ACTIVE) + break; + if(actstrip==NULL) + return; + + /* copy to selected items */ + for (strip=ob->nlastrips.first; strip; strip=strip->next){ + if (strip->flag & ACTSTRIP_SELECT) { + if(strip!=actstrip) { + if (strip->modifiers.first) + BLI_freelistN(&strip->modifiers); + if (actstrip->modifiers.first) + duplicatelist (&strip->modifiers, &actstrip->modifiers); + } + } + } + + BIF_undo_push("Copy Action Modifiers"); + allqueue(REDRAWNLA, 0); + DAG_scene_flush_update(G.scene, screen_view3d_layers()); +} + |