diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index af104a88fed..3844cdfcbfb 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -206,6 +206,14 @@ void relink_constraints (struct ListBase *list) bRigidBodyJointConstraint *data; data = con->data; + ID_NEW(data->tar); + } + break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + data = con->data; + ID_NEW(data->tar); } break; @@ -333,6 +341,13 @@ char constraint_has_target (bConstraint *con) return 1; } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = con->data; + if (data->tar) + return 1; + } + break; } // Unknown types or CONSTRAINT_TYPE_NULL or no target return 0; @@ -422,6 +437,13 @@ Object *get_constraint_target(bConstraint *con, char **subtarget) return data->tar; } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = con->data; + *subtarget= NULL; + return data->tar; + } + break; default: *subtarget= NULL; break; @@ -511,6 +533,12 @@ void set_constraint_target(bConstraint *con, Object *ob, char *subtarget) if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = con->data; + data->tar= ob; + } + break; } } @@ -739,6 +767,13 @@ void *new_constraint_data (short type) result = data; } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + data = MEM_callocN(sizeof(bClampToConstraint), "ClampToConstraint"); + result = data; + } + break; default: result = NULL; @@ -1255,6 +1290,24 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void* own Mat4One (mat); } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + data = (bClampToConstraint*)con->data; + + if (data->tar) { + Curve *cu= data->tar->data; + + /* note; when creating constraints that follow path, the curve gets the CU_PATH set now, + currently for paths to work it needs to go through the bevlist/displist system (ton) */ + + if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + makeDispListCurveTypes(data->tar, 0); + } + + Mat4One (mat); + } + break; default: Mat4One(mat); @@ -1277,7 +1330,7 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype, Mat4One (M_identity); - switch (constraint->type){ + switch (constraint->type) { case CONSTRAINT_TYPE_NULL: case CONSTRAINT_TYPE_KINEMATIC: /* removed */ break; @@ -1300,10 +1353,8 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype, data = constraint->data; - if (data->flag & LOCLIKE_OFFSET) { - // for now... + if (data->flag & LOCLIKE_OFFSET) VECCOPY(offset, ob->obmat[3]); - } if (data->flag & LOCLIKE_X) { ob->obmat[3][0] = targetmat[3][0]; @@ -2181,7 +2232,77 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype, } - break; + break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + Curve *cu; + float obmat[4][4], targetMatrix[4][4], ownLoc[3]; + float curveMin[3], curveMax[3]; + + data = constraint->data; + + /* prevent crash if user deletes curve */ + if ((data->tar == NULL) || (data->tar->type != OB_CURVE) ) + return; + else + cu= data->tar->data; + + Mat4CpyMat4(obmat, ob->obmat); + Mat4One(targetMatrix); + VECCOPY(ownLoc, obmat[3]); + + INIT_MINMAX(curveMin, curveMax) + minmax_object(data->tar, curveMin, curveMax); + + /* get targetmatrix */ + if(cu->path && cu->path->data) { + float vec[4], dir[3], totmat[4][4]; + float curvetime; + short clamp_axis; + + /* find best position on curve */ + /* 1. determine which axis to sample on? */ + if (data->flag==CLAMPTO_AUTO) { + float size[3]; + VecSubf(size, curveMax, curveMin); + + /* find axis along which the bounding box has the greatest + * extent. Otherwise, default to the x-axis, as that is quite + * frequently used. + */ + if ((size[2]>size[0]) && (size[2]>size[1])) + clamp_axis= CLAMPTO_Z; + else if ((size[1]>size[0]) && (size[1]>size[2])) + clamp_axis= CLAMPTO_Y; + else + clamp_axis = CLAMPTO_X; + } + else + clamp_axis= data->flag; + + /* 2. determine position relative to curve on a 0-1 scale */ + if (clamp_axis > 0) clamp_axis--; + if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) + curvetime = 0.0; + else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) + curvetime = 1.0; + else + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); // umm + + /* 3. position on curve */ + if(where_on_path(data->tar, curvetime, vec, dir) ) { + Mat4One(totmat); + VECCOPY(totmat[3], vec); + + Mat4MulSerie(targetMatrix, data->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL); + } + } + + /* obtain final object position */ + VECCOPY(ob->obmat[3], targetMatrix[3]); + } + break; default: printf ("Error: Unknown constraint type\n"); break; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 686606e0a13..6ef6f18caee 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1710,6 +1710,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data->tar = newlibadr(fd, id->lib, data->tar); }; break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data; + data= ((bClampToConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + }; + break; case CONSTRAINT_TYPE_NULL: break; @@ -6852,6 +6859,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) expand_doit(fd, mainvar, data->tar); break; } + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = (bClampToConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + break; + } case CONSTRAINT_TYPE_NULL: break; default: diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2d9a14a50d2..0d4d9d82ee1 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -744,6 +744,9 @@ static void write_constraints(WriteData *wd, ListBase *conlist) case CONSTRAINT_TYPE_RIGIDBODYJOINT: writestruct(wd, DATA, "bRigidBodyJointConstraint", 1, con->data); break; + case CONSTRAINT_TYPE_CLAMPTO: + writestruct(wd, DATA, "bClampToConstraint", 1, con->data); + break; default: break; } diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index eb6a9bfeebb..bde3db33376 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -646,6 +646,7 @@ enum { B_CONSTRAINT_ADD_RIGIDBODYJOINT, B_CONSTRAINT_ADD_CHILDOF, B_CONSTRAINT_ADD_PYTHON, + B_CONSTRAINT_ADD_CLAMPTO, B_CONSTRAINT_INF }; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6cf1403b803..bb4065605e7 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -216,6 +216,13 @@ typedef struct bRigidBodyJointConstraint{ short pad2; } bRigidBodyJointConstraint; +/* ClampTo Constraint */ +typedef struct bClampToConstraint { + Object *tar; /* 'target' must be a curve */ + int flag; /* which plane to find object on */ + int pad; +} bClampToConstraint; + /* bConstraint.type */ #define CONSTRAINT_TYPE_NULL 0 #define CONSTRAINT_TYPE_CHILDOF 1 /* Unimplemented */ @@ -235,6 +242,7 @@ typedef struct bRigidBodyJointConstraint{ #define CONSTRAINT_TYPE_STRETCHTO 15 /* claiming this to be mine :) is in tuhopuu bjornmose */ #define CONSTRAINT_TYPE_MINMAX 16 /* floor constraint */ #define CONSTRAINT_TYPE_RIGIDBODYJOINT 17 /* rigidbody constraint */ +#define CONSTRAINT_TYPE_CLAMPTO 18 /* clampto constraint */ /* bConstraint.flag */ /* expand for UI */ @@ -310,6 +318,11 @@ typedef struct bRigidBodyJointConstraint{ #define PLANE_Y 0x01 #define PLANE_Z 0x02 +#define CLAMPTO_AUTO 0 +#define CLAMPTO_X 1 +#define CLAMPTO_Y 2 +#define CLAMPTO_Z 3 + /* bKinematicConstraint->flag */ #define CONSTRAINT_IK_TIP 1 #define CONSTRAINT_IK_ROT 2 diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 5cb5f4671bd..411422bef9a 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -371,6 +371,9 @@ void get_constraint_typestring (char *str, void *con_v) case CONSTRAINT_TYPE_RIGIDBODYJOINT: strcpy (str, "Rigid Body"); return; + case CONSTRAINT_TYPE_CLAMPTO: + strcpy (str, "Clamp To"); + return; default: strcpy (str, "Unknown"); return; @@ -1268,6 +1271,28 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s } } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = con->data; + + height = 66; + 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 */ + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); + + /* Draw XYZ toggles */ + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Main Axis:", *xco, *yco-64, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Auto", *xco+100, *yco-64, 50, 18, &data->flag, 12.0, CLAMPTO_AUTO, 0, 0, "Automatically determine main-axis of movement"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "X", *xco+150, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_X, 0, 0, "Main axis of movement is x-axis"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Y", *xco+182, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Y, 0, 0, "Main axis of movement is y-axis"); + uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Z", *xco+214, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Z, 0, 0, "Main axis of movement is z-axis"); + uiBlockEndAlign(block); + } + break; case CONSTRAINT_TYPE_NULL: { height = 17; @@ -1327,6 +1352,7 @@ static uiBlock *add_constraintmenu(void *arg_unused) uiDefBut(block, BUTM, B_CONSTRAINT_ADD_MINMAX,"Floor", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCKTRACK,"Locked Track", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_FOLLOWPATH,"Follow Path", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CLAMPTO,"Clamp To", 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, ""); @@ -1515,6 +1541,15 @@ void do_constraintbuts(unsigned short event) BIF_undo_push("Add constraint"); } break; + case B_CONSTRAINT_ADD_CLAMPTO: + { + bConstraint *con; + con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO); + 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 f1b35901c0c..f9e8175b1d1 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -313,6 +313,12 @@ char *get_con_subtarget_name(bConstraint *con, Object *target) return NULL; } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + /* cannot have subtarget. if followpath is removed from here, remove this too... */ + return NULL; + } + break; } return NULL; @@ -571,6 +577,29 @@ static void test_constraints (Object *owner, const char* substring) } } break; + case CONSTRAINT_TYPE_CLAMPTO: + { + bClampToConstraint *data = curcon->data; + + if (!exist_object(data->tar)){ + data->tar = NULL; + curcon->flag |= CONSTRAINT_DISABLE; + break; + } + + if (data->tar->type != OB_CURVE){ + data->tar = NULL; + curcon->flag |= CONSTRAINT_DISABLE; + break; + } + else { + Curve *cu= data->tar->data; + + /* auto-set 'Path' setting on curve so this works */ + cu->flag |= CU_PATH; + } + } + break; } } } @@ -661,7 +690,7 @@ void add_constraint(int only_IK) if(pchansel) nr= pupmenu("Add Constraint to Active Bone%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16"); else if(obsel && obsel->type==OB_CURVE) - nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Stretch To%x7|Action%x16"); + nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|Action%x16"); else if(obsel) nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16"); else @@ -669,7 +698,7 @@ void add_constraint(int only_IK) } else { if(obsel && obsel->type==OB_CURVE) - nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6"); + nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17"); else if(obsel) nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5"); else @@ -728,6 +757,11 @@ void add_constraint(int only_IK) else if(nr==14) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIMIT); else if(nr==15) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIMIT); else if(nr==16) con = add_new_constraint(CONSTRAINT_TYPE_ACTION); + else if(nr==17) { + Curve *cu= obsel->data; + cu->flag |= CU_PATH; + con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO) + } if(con==NULL) return; /* paranoia */