diff options
Diffstat (limited to 'source/blender/blenkernel/intern/constraint.c')
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 493 |
1 files changed, 280 insertions, 213 deletions
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b668a1f214d..c055a0ca6a7 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -31,18 +31,21 @@ #include <stddef.h> #include <string.h> #include <math.h> +#include <float.h> #include "MEM_guardedalloc.h" -#include "nla.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "BLI_editVert.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_lattice_types.h" #include "DNA_scene_types.h" @@ -63,12 +66,14 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_idprop.h" +#include "BKE_shrinkwrap.h" +#include "BKE_mesh.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" #endif -#include "blendef.h" +#include "ED_mesh.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -79,157 +84,6 @@ #endif -/* ******************* Constraint Channels ********************** */ -/* Constraint Channels exist in one of two places: - * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels) - * - Under Object without Object-level Action yet (ob->constraintChannels) - * - * The main purpose that Constraint Channels serve is to act as a link - * between an IPO-block (which provides values to interpolate between for some settings) - */ - -/* ------------ Data Management ----------- */ - -/* Free constraint channels, and reduce the number of users of the related ipo-blocks */ -void free_constraint_channels (ListBase *chanbase) -{ - bConstraintChannel *chan; - - for (chan=chanbase->first; chan; chan=chan->next) { - if (chan->ipo) { - chan->ipo->id.us--; - } - } - - BLI_freelistN(chanbase); -} - -/* Make a copy of the constraint channels from dst to src, and also give the - * new constraint channels their own copy of the original's IPO. - */ -void copy_constraint_channels (ListBase *dst, ListBase *src) -{ - bConstraintChannel *dchan, *schan; - - dst->first = dst->last = NULL; - duplicatelist(dst, src); - - for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { - dchan->ipo = copy_ipo(schan->ipo); - } -} - -/* Make a copy of the constraint channels from dst to src, but make the - * new constraint channels use the same IPO-data as their twin. - */ -void clone_constraint_channels (ListBase *dst, ListBase *src) -{ - bConstraintChannel *dchan, *schan; - - dst->first = dst->last = NULL; - duplicatelist(dst, src); - - for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { - id_us_plus((ID *)dchan->ipo); - } -} - -/* ------------- Constraint Channel Tools ------------ */ - -/* Find the constraint channel with a given name */ -bConstraintChannel *get_constraint_channel (ListBase *list, const char name[]) -{ - bConstraintChannel *chan; - - if (list) { - for (chan = list->first; chan; chan=chan->next) { - if (!strcmp(name, chan->name)) { - return chan; - } - } - } - - return NULL; -} - -/* Find or create a new constraint channel */ -bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[]) -{ - bConstraintChannel *chan; - - chan= get_constraint_channel(list, name); - - if (chan == NULL) { - chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint channel"); - BLI_addtail(list, chan); - strcpy(chan->name, name); - } - - return chan; -} - -/* --------- Constraint Channel Evaluation/Execution --------- */ - -/* IPO-system call: calculate IPO-block for constraint channels, and flush that - * info onto the corresponding constraint. - */ -void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, short onlydrivers) -{ - bConstraint *con; - - /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */ - for (con=conbase->first; con; con=con->next) { - Ipo *ipo= NULL; - - if (con->flag & CONSTRAINT_OWN_IPO) - ipo= con->ipo; - else { - bConstraintChannel *chan = get_constraint_channel(chanbase, con->name); - if (chan) ipo= chan->ipo; - } - - if (ipo) { - IpoCurve *icu; - - calc_ipo(ipo, ctime); - - for (icu=ipo->curve.first; icu; icu=icu->next) { - if (!onlydrivers || icu->driver) { - switch (icu->adrcode) { - case CO_ENFORCE: - { - /* Influence is clamped to 0.0f -> 1.0f range */ - con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); - } - break; - case CO_HEADTAIL: - { - /* we need to check types of constraints that can get this here, as user - * may have created an IPO-curve for this from IPO-editor but for a constraint - * that cannot support this - */ - switch (con->type) { - /* supported constraints go here... */ - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRACKTO: - case CONSTRAINT_TYPE_MINMAX: - case CONSTRAINT_TYPE_STRETCHTO: - case CONSTRAINT_TYPE_DISTLIMIT: - con->headtail = icu->curval; - break; - - default: - /* not supported */ - break; - } - } - break; - } - } - } - } - } -} /* ************************ Constraints - General Utilities *************************** */ /* These functions here don't act on any specific constraints, and are therefore should/will @@ -242,20 +96,23 @@ void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, /* Find the first available, non-duplicate name for a given constraint */ void unique_constraint_name (bConstraint *con, ListBase *list) { - BLI_uniquename(list, con, "Const", offsetof(bConstraint, name), 32); + BLI_uniquename(list, con, "Const", '.', offsetof(bConstraint, name), 32); } /* ----------------- Evaluation Loop Preparation --------------- */ /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatype) +bConstraintOb *constraints_make_evalob (Scene *scene, Object *ob, void *subdata, short datatype) { bConstraintOb *cob; /* create regardless of whether we have any data! */ cob= MEM_callocN(sizeof(bConstraintOb), "bConstraintOb"); + /* for system time, part of deglobalization, code nicer later with local time (ton) */ + cob->scene= scene; + /* based on type of available data */ switch (datatype) { case CONSTRAINT_OBTYPE_OBJECT: @@ -533,13 +390,16 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 /* ------------ General Target Matrix Tools ---------- */ /* function that sets the given matrix based on given vertex group in mesh */ -static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) +static void contarget_get_mesh_mat (Scene *scene, Object *ob, char *substring, float mat[][4]) { DerivedMesh *dm; + Mesh *me= ob->data; + EditMesh *em = BKE_mesh_get_editmesh(me); float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3]; float imat[3][3], tmat[3][3]; int dgroup; + short freeDM = 0; /* initialize target matrix using target matrix */ Mat4CpyMat4(mat, ob->obmat); @@ -549,13 +409,22 @@ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) if (dgroup < 0) return; /* get DerivedMesh */ - if ((G.obedit == ob) && (G.editMesh)) { + if (em) { /* target is in editmode, so get a special derived mesh */ - dm = CDDM_from_editmesh(G.editMesh, ob->data); + dm = CDDM_from_editmesh(em, ob->data); + freeDM= 1; } else { - /* when not in EditMode, this should exist */ - dm = (DerivedMesh *)ob->derivedFinal; + /* when not in EditMode, use the 'final' derived mesh + * - check if the custom data masks for derivedFinal mean that we can just use that + * (this is more effficient + sufficient for most cases) + */ + if (ob->lastDataMask != CD_MASK_DERIVEDMESH) { + dm = mesh_get_derived_final(scene, ob, CD_MASK_DERIVEDMESH); + freeDM= 1; + } + else + dm = (DerivedMesh *)ob->derivedFinal; } /* only continue if there's a valid DerivedMesh */ @@ -621,9 +490,10 @@ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) } /* free temporary DerivedMesh created (in EditMode case) */ - if (G.editMesh) { - if (dm) dm->release(dm); - } + if (dm && freeDM) + dm->release(dm); + if (em) + BKE_mesh_end_editmesh(me, em); } /* function that sets the given matrix based on given vertex group in lattice */ @@ -685,7 +555,7 @@ static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][ /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to, float headtail) +static void constraint_target_to_mat4 (Scene *scene, Object *ob, char *substring, float mat[][4], short from, short to, float headtail) { /* Case OBJECT */ if (!strlen(substring)) { @@ -702,7 +572,7 @@ static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][ * way as constraints can only really affect things on object/bone level. */ else if (ob->type == OB_MESH) { - contarget_get_mesh_mat(ob, substring, mat); + contarget_get_mesh_mat(scene, ob, substring, mat); constraint_mat_convertspace(ob, NULL, mat, from, to); } else if (ob->type == OB_LATTICE) { @@ -784,7 +654,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) { if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) Mat4One(ct->matrix); } @@ -1199,7 +1069,7 @@ static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstra bKinematicConstraint *data= con->data; if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) { if (data->flag & CONSTRAINT_IK_AUTO) { Object *ob= cob->ob; @@ -1293,15 +1163,17 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr /* only happens on reload file, but violates depsgraph still... fix! */ if (cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); if (cu->path && cu->path->data) { - curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset; + curvetime= bsystem_time(cob->scene, ct->tar, (float)ctime, 0.0) - data->offset; +#if 0 // XXX old animation system if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) { curvetime /= cu->pathlen; CLAMP(curvetime, 0.0, 1.0); } +#endif // XXX old animation system if ( where_on_path(ct->tar, curvetime, vec, dir) ) { if (data->followflag) { @@ -1843,7 +1715,7 @@ static void pycon_copy (bConstraint *con, bConstraint *srccon) bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; pycon->prop = IDP_CopyProperty(opycon->prop); - duplicatelist(&pycon->targets, &opycon->targets); + BLI_duplicatelist(&pycon->targets, &opycon->targets); } static void pycon_new_data (void *cdata) @@ -1881,13 +1753,13 @@ static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintT /* this check is to make sure curve objects get updated on file load correctly.*/ if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); } /* firstly calculate the matrix the normal way, then let the py-function override * this matrix if it needs to do so */ - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* only execute target calculation if allowed */ #ifndef DISABLE_PYTHON @@ -1994,7 +1866,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint Mat4One(ct->matrix); /* get the transform matrix of the target */ - constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* determine where in transform range target is */ /* data->type is mapped as follows for backwards compatability: @@ -2026,28 +1898,38 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint CLAMP(s, 0, 1); t = ( s * (data->end-data->start)) + data->start; + if (G.f & G_DEBUG) + printf("do Action Constraint %s - Ob %s Pchan %s \n", con->name, cob->ob->id.name+2, (cob->pchan)?cob->pchan->name:NULL); + /* Get the appropriate information from the action */ if (cob->type == CONSTRAINT_OBTYPE_BONE) { + Object workob; bPose *pose; bPoseChannel *pchan, *tchan; /* make a temporary pose and evaluate using that */ pose = MEM_callocN(sizeof(bPose), "pose"); + /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set */ pchan = cob->pchan; tchan= verify_pose_channel(pose, pchan->name); - extract_pose_from_action(pose, data->act, t); - chan_calc_mat(tchan); + /* evaluate action using workob (it will only set the PoseChannel in question) */ + what_does_obaction(cob->scene, cob->ob, &workob, pose, data->act, pchan->name, t); + /* convert animation to matrices for use here */ + chan_calc_mat(tchan); Mat4CpyMat4(ct->matrix, tchan->chan_mat); /* Clean up */ free_pose(pose); } else if (cob->type == CONSTRAINT_OBTYPE_OBJECT) { + Object workob; + /* evaluate using workob */ - what_does_obaction(cob->ob, data->act, t); + // FIXME: we don't have any consistent standards on limiting effects on object... + what_does_obaction(cob->scene, cob->ob, &workob, NULL, data->act, NULL, t); object_to_mat4(&workob, ct->matrix); } else { @@ -2962,7 +2844,7 @@ static void clampto_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain /* only happens on reload file, but violates depsgraph still... fix! */ if (cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); } /* technically, this isn't really needed for evaluation, but we don't know what else @@ -3022,44 +2904,53 @@ static void clampto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta float len= (curveMax[clamp_axis] - curveMin[clamp_axis]); float offset; - /* find bounding-box range where target is located */ - if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { - /* bounding-box range is before */ - offset= curveMin[clamp_axis]; - - while (ownLoc[clamp_axis] < offset) - offset -= len; - - /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { - /* bounding-box range is after */ - offset= curveMax[clamp_axis]; - - while (ownLoc[clamp_axis] > offset) { - if ((offset + len) > ownLoc[clamp_axis]) - break; - else - offset += len; + /* check to make sure len is not so close to zero that it'll cause errors */ + if (IS_EQ(len, 0) == 0) { + /* find bounding-box range where target is located */ + if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { + /* bounding-box range is before */ + offset= curveMin[clamp_axis]; + + while (ownLoc[clamp_axis] < offset) + offset -= len; + + /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { + /* bounding-box range is after */ + offset= curveMax[clamp_axis]; + + while (ownLoc[clamp_axis] > offset) { + if ((offset + len) > ownLoc[clamp_axis]) + break; + else + offset += len; + } + + /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else { + /* as the location falls within bounds, just calculate */ + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); } - - /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); } else { - /* as the location falls within bounds, just calculate */ - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); + /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */ + curvetime= 0.0f; } } else { /* no cyclic, so position is clamped to within the bounding box */ if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) - curvetime = 0.0; + curvetime = 0.0f; else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) - curvetime = 1.0; - else + curvetime = 1.0f; + else if ( IS_EQ((curveMax[clamp_axis] - curveMin[clamp_axis]), 0) == 0 ) curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); + else + curvetime = 0.0f; } /* 3. position on curve */ @@ -3230,9 +3121,168 @@ static bConstraintTypeInfo CTI_TRANSFORM = { transform_evaluate /* evaluate */ }; +/* ---------- Shrinkwrap Constraint ----------- */ + +static int shrinkwrap_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct; + + SINGLETARGETNS_GET_TARS(con, data->target, ct, list) + + return 1; + } + + return 0; +} + + +static void shrinkwrap_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bShrinkwrapConstraint *data = con->data; + bConstraintTarget *ct= list->first; + + SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, nocopy) + } +} + + +static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) +{ + bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; + + if( VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) + { + int fail = FALSE; + float co[3] = {0.0f, 0.0f, 0.0f}; + float no[3] = {0.0f, 0.0f, 0.0f}; + float dist; + + SpaceTransform transform; + DerivedMesh *target = object_get_derived_final(cob->scene, ct->tar, CD_MASK_BAREMESH); + BVHTreeRayHit hit; + BVHTreeNearest nearest; + + BVHTreeFromMesh treeData; + memset( &treeData, 0, sizeof(treeData) ); + + nearest.index = -1; + nearest.dist = FLT_MAX; + + hit.index = -1; + hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it + + Mat4One(ct->matrix); + + if(target != NULL) + { + space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat); + + switch(scon->shrinkType) + { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + case MOD_SHRINKWRAP_NEAREST_VERTEX: + + if(scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) + bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); + else + bvhtree_from_mesh_faces(&treeData, target, 0.0, 2, 6); + + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + space_transform_apply(&transform, co); + + BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); + + dist = VecLenf(co, nearest.co); + VecLerpf(co, co, nearest.co, (dist - scon->dist)/dist); /* linear interpolation */ + space_transform_invert(&transform, co); + break; + + case MOD_SHRINKWRAP_PROJECT: + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; + if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; + + if(INPR(no,no) < FLT_EPSILON) + { + fail = TRUE; + break; + } + + Normalize(no); + + + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); + if(treeData.tree == NULL) + { + fail = TRUE; + break; + } + + if(normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) + { + fail = TRUE; + break; + } + VECCOPY(co, hit.co); + break; + } + + free_bvhtree_from_mesh(&treeData); + + target->release(target); + + if(fail == TRUE) + { + /* Don't move the point */ + co[0] = co[1] = co[2] = 0.0f; + } + + /* co is in local object coordinates, change it to global and update target position */ + VecMat4MulVecfl(co, cob->matrix, co); + VECCOPY(ct->matrix[3], co); + } + } +} + +static void shrinkwrap_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) + { + VECCOPY(cob->matrix[3], ct->matrix[3]); + } +} + +static bConstraintTypeInfo CTI_SHRINKWRAP = { + CONSTRAINT_TYPE_SHRINKWRAP, /* type */ + sizeof(bShrinkwrapConstraint), /* size */ + "Shrinkwrap", /* name */ + "bShrinkwrapConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + NULL, /* new data */ + shrinkwrap_get_tars, /* get constraint targets */ + shrinkwrap_flush_tars, /* flush constraint targets */ + shrinkwrap_get_tarmat, /* get a target matrix */ + shrinkwrap_evaluate /* evaluate */ +}; + + + /* ************************* Constraints Type-Info *************************** */ /* All of the constraints api functions use bConstraintTypeInfo structs to carry out - * and operations that involve constraint specifc code. + * and operations that involve constraint specific code. */ /* These globals only ever get directly accessed in this file */ @@ -3261,6 +3311,7 @@ static void constraints_init_typeinfo () { constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ + constraintsTypeInfo[20]= &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */ } /* This function should be used for getting the appropriate type-info when only @@ -3323,17 +3374,16 @@ void free_constraint_data (bConstraint *con) } /* Free all constraints from a constraint-stack */ -void free_constraints (ListBase *conlist) +void free_constraints (ListBase *list) { bConstraint *con; /* Free constraint data and also any extra data */ - for (con= conlist->first; con; con= con->next) { + for (con= list->first; con; con= con->next) free_constraint_data(con); - } /* Free the whole list */ - BLI_freelistN(conlist); + BLI_freelistN(list); } /* Reassign links that constraints have to other data (called during file loading?) */ @@ -3372,9 +3422,9 @@ void copy_constraints (ListBase *dst, ListBase *src) bConstraint *con, *srccon; dst->first= dst->last= NULL; - duplicatelist(dst, src); + BLI_duplicatelist(dst, src); - for (con=dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) { + for (con=dst->first, srccon=src->first; con && srccon; srccon=srccon->next, con=con->next) { bConstraintTypeInfo *cti= constraint_get_typeinfo(con); /* make a new copy of the constraint's data */ @@ -3386,6 +3436,23 @@ void copy_constraints (ListBase *dst, ListBase *src) } } +/* finds the 'active' constraint in a constraint stack */ +bConstraint *constraints_get_active (ListBase *list) +{ + bConstraint *con; + + /* search for the first constraint with the 'active' flag set */ + if (list) { + for (con= list->first; con; con= con->next) { + if (con->flag & CONSTRAINT_ACTIVE) + return con; + } + } + + /* no active constraint found */ + return NULL; +} + /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ @@ -3535,7 +3602,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) if (con->enforce == 0.0f) continue; /* influence of constraint - * - value should have been set from IPO's/Constraint Channels already + * - value should have been set from animation data already */ enf = con->enforce; |