diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7d7180da271..38f25b54fd8 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2382,6 +2382,118 @@ static bConstraintTypeInfo CTI_LOCKTRACK = { locktrack_evaluate /* evaluate */ }; +/* ---------- Limit Distance Constraint ----------- */ + +static void distlimit_new_data (void *cdata) +{ + bDistLimitConstraint *data= (bDistLimitConstraint *)cdata; + + data->dist= 0.0; +} + +static void distlimit_get_tars (bConstraint *con, ListBase *list) +{ + if (con && list) { + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct; + + /* standard target-getting macro for single-target constraints */ + SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + } +} + +static void distlimit_flush_tars (bConstraint *con, ListBase *list, short nocopy) +{ + if (con && list) { + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct= list->first; + + /* the following macro is used for all standard single-target constraints */ + SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy) + } +} + +static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bDistLimitConstraint *data= con->data; + bConstraintTarget *ct= targets->first; + + /* only evaluate if there is a target */ + if (VALID_CONS_TARGET(ct)) { + float dvec[3], dist=0.0f, sfac=1.0f; + short clamp_surf= 0; + + /* calculate our current distance from the target */ + dist= VecLenf(cob->matrix[3], ct->matrix[3]); + + /* set distance (flag is only set when user demands it) */ + if (data->dist == 0) + data->dist= dist; + + /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */ + if (data->mode == LIMITDIST_OUTSIDE) { + /* if inside, then move to surface */ + if (dist <= data->dist) { + clamp_surf= 1; + sfac= data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + if (dist <= (data->dist + data->soft)) { + + } + } + } + else if (data->mode == LIMITDIST_INSIDE) { + /* if outside, then move to surface */ + if (dist >= data->dist) { + clamp_surf= 1; + sfac= data->dist / dist; + } + /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ + else if (data->flag & LIMITDIST_USESOFT) { + // FIXME: there's a problem with "jumping" when this kicks in + if (dist >= (data->dist - data->soft)) { + sfac = data->soft*(1.0 - exp(-(dist - data->dist)/data->soft)) + data->dist; + sfac /= dist; + + clamp_surf= 1; + } + } + } + else { + if (IS_EQ(dist, data->dist)==0) { + clamp_surf= 1; + sfac= data->dist / dist; + } + } + + /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */ + if (clamp_surf) { + /* simply interpolate along line formed by target -> owner */ + VecLerpf(dvec, ct->matrix[3], cob->matrix[3], sfac); + + /* copy new vector onto owner */ + VECCOPY(cob->matrix[3], dvec); + } + } +} + +static bConstraintTypeInfo CTI_DISTLIMIT = { + CONSTRAINT_TYPE_DISTLIMIT, /* type */ + sizeof(bDistLimitConstraint), /* size */ + "Limit Distance", /* name */ + "bDistLimitConstraint", /* struct name */ + NULL, /* free data */ + NULL, /* relink data */ + NULL, /* copy data */ + distlimit_new_data, /* new data */ + distlimit_get_tars, /* get constraint targets */ + distlimit_flush_tars, /* flush constraint targets */ + default_get_tarmat, /* get a target matrix */ + distlimit_evaluate /* evaluate */ +}; + /* ---------- Stretch To ------------ */ static void stretchto_new_data (void *cdata) @@ -3067,12 +3179,12 @@ static void constraints_init_typeinfo () { constraintsTypeInfo[11]= &CTI_PYTHON; /* Python/Script Constraint */ constraintsTypeInfo[12]= &CTI_ACTION; /* Action Constraint */ constraintsTypeInfo[13]= &CTI_LOCKTRACK; /* Locked-Track Constraint */ - constraintsTypeInfo[14]= NULL; /* 'Distance Limit' Constraint */ + constraintsTypeInfo[14]= &CTI_DISTLIMIT; /* Limit Distance Constraint */ constraintsTypeInfo[15]= &CTI_STRETCHTO; /* StretchTo Constaint */ constraintsTypeInfo[16]= &CTI_MINMAX; /* Floor Constraint */ constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */ - constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ + constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8481e7c0a3a..f3a3a3478ac 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1752,6 +1752,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data->tar = newlibadr(fd, id->lib, data->tar); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data; + data= ((bDistLimitConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; case CONSTRAINT_TYPE_NULL: break; } @@ -1765,6 +1772,7 @@ static void direct_link_constraints(FileData *fd, ListBase *lb) link_list(fd, lb); for (cons=lb->first; cons; cons=cons->next) { cons->data = newdataadr(fd, cons->data); + if (cons->type == CONSTRAINT_TYPE_PYTHON) { bPythonConstraint *data= cons->data; link_list(fd, &data->targets); @@ -7807,6 +7815,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) expand_doit(fd, mainvar, data->tar); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data = (bDistLimitConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; default: break; } diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 6d7a73eec54..a067b3e1489 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -694,7 +694,7 @@ enum { B_CONSTRAINT_ADD_ACTION, B_CONSTRAINT_ADD_LOCKTRACK, B_CONSTRAINT_ADD_FOLLOWPATH, - B_CONSTRAINT_ADD_DISTANCELIMIT, + B_CONSTRAINT_ADD_DISTLIMIT, B_CONSTRAINT_ADD_STRETCHTO, B_CONSTRAINT_ADD_LOCLIMIT, B_CONSTRAINT_ADD_ROTLIMIT, diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 4ae8d6b39e6..2bcf2412588 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -307,6 +307,19 @@ typedef struct bSizeLimitConstraint { short flag2; } bSizeLimitConstraint; +/* Limit Distance Constraint */ +typedef struct bDistLimitConstraint { + Object *tar; + char subtarget[32]; + + float dist; /* distance (radius of clamping sphere) from target */ + float soft; /* distance from clamping-sphere to start applying 'fade' */ + + short flag; /* settings */ + short mode; /* how to limit in relation to clamping sphere */ + int pad; +} bDistLimitConstraint; + /* ------------------------------------------ */ /* bConstraint->type @@ -328,13 +341,14 @@ typedef enum B_CONSTAINT_TYPES { CONSTRAINT_TYPE_PYTHON, /* Unimplemented no longer :) - Aligorith. Scripts */ CONSTRAINT_TYPE_ACTION, CONSTRAINT_TYPE_LOCKTRACK, /* New Tracking constraint that locks an axis in place - theeth */ - CONSTRAINT_TYPE_DISTANCELIMIT, /* was never properly coded - removed! */ + CONSTRAINT_TYPE_DISTLIMIT, /* limit distance */ CONSTRAINT_TYPE_STRETCHTO, /* claiming this to be mine :) is in tuhopuu bjornmose */ CONSTRAINT_TYPE_MINMAX, /* floor constraint */ CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */ CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */ CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */ + /* NOTE: everytime a new constraint is added, update this */ NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM } B_CONSTRAINT_TYPES; @@ -478,6 +492,15 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG { #define LIMIT_NOPARENT 0x01 /* for all Limit constraints - allow to be used during transform? */ #define LIMIT_TRANSFORM 0x02 + +/* distance limit constraint */ + /* bDistLimitConstraint->flag */ +#define LIMITDIST_USESOFT (1<<0) + + /* bDistLimitConstraint->mode */ +#define LIMITDIST_INSIDE 0 +#define LIMITDIST_OUTSIDE 1 +#define LIMITDIST_ONSURFACE 2 /* python constraint -> flag */ #define PYCON_USETARGETS 0x01 diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 1a415b461cb..32218c27ace 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -1439,6 +1439,54 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s draw_constraint_spaceselect(block, con, *xco, *yco-130, is_armature_owner(ob), -1); } break; + case CONSTRAINT_TYPE_DISTLIMIT: + { + bDistLimitConstraint *data = con->data; + + height = 105; + uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); + + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + /* Draw target parameters */ + uiBlockBeginAlign(block); + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + if (is_armature_target(data->tar)) { + but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else if (is_geom_target(data->tar)) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + if (is_armature_target(data->tar)) { + uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60,139,18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Head/Tail:", *xco+155, *yco-60,100,18, &con->headtail, 0.0, 1, 0.1, 0.1, "Target along length of bone: Head=0, Tail=1"); + } + else { + uiDefButF(block, BUT, B_CONSTRAINT_TEST, "R", *xco, *yco-60, 20, 18, &data->dist, 0, 0, 0, 0, "Recalculate distance"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Distance:", *xco+18, *yco-60, 237, 18, &data->dist, 0.0, 100, 0.5, 0.5, "Radius of limiting sphere"); + } + + /* disabled soft-distance controls... currently it doesn't work yet. It was intended to be used for soft-ik (see xsi-blog for details) */ +#if 0 + uiDefButBitS(block, TOG, LIMITDIST_USESOFT, B_CONSTRAINT_TEST, "Soft", *xco, *yco-82, 50, 18, &data->flag, 0, 24, 0, 0, "Enables soft-distance"); + if (data->flag & LIMITDIST_USESOFT) + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Soft-Distance:", *xco+50, *yco-82, 187, 18, &data->soft, 0.0, 100, 0.5, 0.5, "Distance surrounding radius when transforms should get 'delayed'"); +#endif + uiBlockEndAlign(block); + + uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Limit Mode%t|Inside %x0|Outside %x1|Surface %x2", *xco+((width/2)-50), *yco-104, 100, 18, &data->mode, 0, 24, 0, 0, "Distances in relation to sphere of influence to allow"); + } + break; case CONSTRAINT_TYPE_RIGIDBODYJOINT: { bRigidBodyJointConstraint *data = con->data; @@ -1748,6 +1796,7 @@ static uiBlock *add_constraintmenu(void *arg_unused) uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCLIMIT, "Limit Location", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ROTLIMIT, "Limit Rotation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SIZELIMIT, "Limit Scale", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_DISTLIMIT, "Limit Distance", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -1980,6 +2029,14 @@ void do_constraintbuts(unsigned short event) BIF_undo_push("Add constraint"); } break; + case B_CONSTRAINT_ADD_DISTLIMIT: + { + con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT); + add_constraint_to_active(ob, con); + + BIF_undo_push("Add constraint"); + } + break; default: break; diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index ac5129dd021..ba73767387e 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -364,21 +364,21 @@ void add_constraint (short only_IK) else { if (pchanact) { if (pchansel) - nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else if ((obsel) && (obsel->type==OB_CURVE)) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18"); else if (obsel) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); else - nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18"); } else { if ((obsel) && (obsel->type==OB_CURVE)) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18"); else if (obsel) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); else - nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); + nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Limit Distance%x21|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18"); } } @@ -475,6 +475,7 @@ void add_constraint (short only_IK) } } else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM); + else if (nr==21) con = add_new_constraint(CONSTRAINT_TYPE_DISTLIMIT); if (con==NULL) return; /* paranoia */ diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 6fe2e032eed..b3ea3e1931c 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -2515,7 +2515,7 @@ static int match_adr_constraint(ID * id, int blocktype, char *actname, int adrco case CONSTRAINT_TYPE_LOCKTRACK: if (searchtype==2) foundmatch=1; break; - case CONSTRAINT_TYPE_DISTANCELIMIT: + case CONSTRAINT_TYPE_DISTLIMIT: if (searchtype==1) foundmatch=1; break; case CONSTRAINT_TYPE_MINMAX: