Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_lattice.h7
-rw-r--r--source/blender/blenkernel/intern/action.c308
-rw-r--r--source/blender/blenkernel/intern/armature.c37
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c11
-rw-r--r--source/blender/blenkernel/intern/lattice.c89
-rw-r--r--source/blender/blenkernel/intern/nla.c16
-rw-r--r--source/blender/blenkernel/intern/object.c7
-rw-r--r--source/blender/blenloader/intern/readfile.c17
-rw-r--r--source/blender/blenloader/intern/writefile.c7
-rw-r--r--source/blender/include/BIF_editnla.h1
-rw-r--r--source/blender/makesdna/DNA_action_types.h4
-rw-r--r--source/blender/makesdna/DNA_nla_types.h25
-rw-r--r--source/blender/src/drawnla.c135
-rw-r--r--source/blender/src/editnla.c40
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());
+}
+