diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index dfa9ff8c954..d0bfd711357 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -267,6 +267,12 @@ char constraint_has_target (bConstraint *con) if (data->tar) return 1; } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = con->data; + if (data->tar) return 1; + } + break; } /* Unknown types or CONSTRAINT_TYPE_NULL or no target */ @@ -377,6 +383,13 @@ Object *get_constraint_target(bConstraint *con, char **subtarget) return data->tar; } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = con->data; + *subtarget= data->subtarget; + return data->tar; + } + break; default: *subtarget= NULL; break; @@ -484,6 +497,13 @@ void set_constraint_target(bConstraint *con, Object *ob, char *subtarget) if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = con->data; + data->tar= ob; + if (subtarget) BLI_strncpy(data->subtarget, subtarget, 32); + } + break; } } @@ -714,6 +734,18 @@ void *new_constraint_data (short type) result = data; } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data; + data = MEM_callocN(sizeof(bTransformConstraint), "TransformationConstraint"); + + data->map[0]= 0; + data->map[1]= 1; + data->map[2]= 2; + + result = data; + } + break; default: result = NULL; @@ -1504,6 +1536,19 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void *own Mat4One(mat); } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data; + data= (bTransformConstraint *)con->data; + + if (data->tar) { + constraint_target_to_mat4(data->tar, data->subtarget, mat, CONSTRAINT_SPACE_WORLD, con->tarspace); + valid = 1; + } + else + Mat4One(mat); + } + break; default: Mat4One(mat); @@ -2466,8 +2511,114 @@ static void evaluate_constraint (bConstraint *constraint, float ownermat[][4], f } } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data; + + data = constraint->data; + + /* only work if there is a target */ + if (data->tar) { + float loc[3], eul[3], size[3]; + float dvec[3], sval[3]; + short i; + + /* obtain target effect */ + switch (data->from) { + case 2: /* scale */ + { + Mat4ToSize(targetmat, dvec); + } + break; + case 1: /* rotation */ + { + /* copy, and reduce to smallest rotation distance */ + Mat4ToEul(targetmat, dvec); + + /* reduce rotation */ + for (i=0; i<3; i++) + dvec[i]= fmod(dvec[i], M_PI*2); + } + break; + default: /* location */ + { + VECCOPY(dvec, targetmat[3]); + } + break; + } + + /* extract components of owner's matrix */ + VECCOPY(loc, ownermat[3]); + Mat4ToEul(ownermat, eul); + Mat4ToSize(ownermat, size); + + /* determine where in range current transforms lie */ + if (data->expo) { + for (i=0; i<3; i++) { + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + else { + /* clamp transforms out of range */ + for (i=0; i<3; i++) { + CLAMP(dvec[i], data->from_min[i], data->from_max[i]); + if (data->from_max[i] - data->from_min[i]) + sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]); + else + sval[i]= 0.0f; + } + } + + /* convert radian<->degree */ + if (data->from==1 && data->to==0) { + /* from radians to degrees */ + for (i=0; i<3; i++) + sval[i] = sval[i] / M_PI * 180; + } + else if (data->from==0 && data->to==1) { + /* from degrees to radians */ + for (i=0; i<3; i++) + sval[i] = sval[i] / 180 * M_PI; + } + else if (data->from == data->to == 1) { + /* degrees to radians */ + for (i=0; i<3; i++) + sval[i] = sval[i] / 180 * M_PI; + } + + /* apply transforms */ + switch (data->to) { + case 2: /* scaling */ + for (i=0; i<3; i++) + size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])); + break; + case 1: /* rotation */ + for (i=0; i<3; i++) { + float tmin, tmax; + + /* convert destination min/max ranges from degrees to radians */ + tmin= data->to_min[i] / M_PI * 180; + tmax= data->to_max[i] / M_PI * 180; + + eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); + } + break; + default: /* location */ + for (i=0; i<3; i++) + loc[i] += (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]))); + break; + } + + /* apply to matrix */ + LocEulSizeToMat4(ownermat, loc, eul, size); + } + } + break; default: - printf ("Error: Unknown constraint type\n"); + printf("Error: Unknown constraint type\n"); break; } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b8323cbed81..e5fdebae89d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1712,6 +1712,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) data->tar = newlibadr(fd, id->lib, data->tar); } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data; + data= ((bTransformConstraint*)con->data); + data->tar = newlibadr(fd, id->lib, data->tar); + } + break; case CONSTRAINT_TYPE_NULL: break; } @@ -7095,6 +7102,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) expand_doit(fd, mainvar, data->tar); } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = (bTransformConstraint*)curcon->data; + expand_doit(fd, mainvar, data->tar); + } + break; default: break; } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 5b29703fe35..ca63b860f6c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -760,6 +760,9 @@ static void write_constraints(WriteData *wd, ListBase *conlist) case CONSTRAINT_TYPE_CLAMPTO: writestruct(wd, DATA, "bClampToConstraint", 1, con->data); break; + case CONSTRAINT_TYPE_TRANSFORM: + writestruct(wd, DATA, "bTransformConstraint", 1, con->data); + break; default: break; } diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 142d2ae1d0b..4a106fb5b96 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -649,6 +649,7 @@ enum { B_CONSTRAINT_ADD_CHILDOF, B_CONSTRAINT_ADD_PYTHON, B_CONSTRAINT_ADD_CLAMPTO, + B_CONSTRAINT_ADD_TRANSFORM, B_CONSTRAINT_INF }; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index ce2b558e714..9a0d5a095e5 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -210,13 +210,29 @@ typedef struct bClampToConstraint { /* Child Of Constraint */ typedef struct bChildOfConstraint { - Object *tar; /* object which may/may not be the parent */ + Object *tar; /* object which will act as parent (or target comes from) */ int flag; /* settings */ int pad; float invmat[4][4]; /* parent-inverse matrix to use */ char subtarget[32]; /* string to specify a subobject target */ } bChildOfConstraint; +/* Generic Transform->Transform Constraint */ +typedef struct bTransformConstraint { + Object *tar; /* target (i.e. 'driver' object/bone) */ + char subtarget[32]; + + short from, to; /* can be loc(0) , rot(1), or size(2) */ + char map[3]; /* defines which target-axis deform is copied by each owner-axis */ + char expo; /* extrapolate motion? if 0, confine to ranges */ + + float from_min[3]; /* from_min/max defines range of target transform */ + float from_max[3]; /* to map on to to_min/max range. */ + + float to_min[3]; /* range of motion on owner caused by target */ + float to_max[3]; +} bTransformConstraint; + /* transform limiting constraints - zero target ---------------------------- */ /* Limit Location Constraint */ typedef struct bLocLimitConstraint { @@ -247,26 +263,27 @@ typedef struct bSizeLimitConstraint { /* bConstraint.type */ #define CONSTRAINT_TYPE_NULL 0 -#define CONSTRAINT_TYPE_CHILDOF 1 /* Unimplemented non longer :) - during constraints recode, Aligorith */ +#define CONSTRAINT_TYPE_CHILDOF 1 /* Unimplemented non longer :) - during constraints recode, Aligorith */ #define CONSTRAINT_TYPE_TRACKTO 2 #define CONSTRAINT_TYPE_KINEMATIC 3 #define CONSTRAINT_TYPE_FOLLOWPATH 4 -#define CONSTRAINT_TYPE_ROTLIMIT 5 /* Unimplemented no longer :) - Aligorith */ -#define CONSTRAINT_TYPE_LOCLIMIT 6 /* Unimplemented no longer :) - Aligorith */ -#define CONSTRAINT_TYPE_SIZELIMIT 7 /* Unimplemented no longer :) - Aligorith */ +#define CONSTRAINT_TYPE_ROTLIMIT 5 /* Unimplemented no longer :) - Aligorith */ +#define CONSTRAINT_TYPE_LOCLIMIT 6 /* Unimplemented no longer :) - Aligorith */ +#define CONSTRAINT_TYPE_SIZELIMIT 7 /* Unimplemented no longer :) - Aligorith */ #define CONSTRAINT_TYPE_ROTLIKE 8 #define CONSTRAINT_TYPE_LOCLIKE 9 #define CONSTRAINT_TYPE_SIZELIKE 10 -#define CONSTRAINT_TYPE_PYTHON 11 /* Unimplemented no longer :) - Aligorith. Scripts */ +#define CONSTRAINT_TYPE_PYTHON 11 /* Unimplemented no longer :) - Aligorith. Scripts */ #define CONSTRAINT_TYPE_ACTION 12 -#define CONSTRAINT_TYPE_LOCKTRACK 13 /* New Tracking constraint that locks an axis in place - theeth */ -#define CONSTRAINT_TYPE_DISTANCELIMIT 14 /* was never properly coded - removed! */ -#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 */ +#define CONSTRAINT_TYPE_LOCKTRACK 13 /* New Tracking constraint that locks an axis in place - theeth */ +#define CONSTRAINT_TYPE_DISTANCELIMIT 14 /* was never properly coded - removed! */ +#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 */ +#define CONSTRAINT_TYPE_TRANSFORM 19 /* transformation constraint */ -/* bConstraint.flag */ +/* bConstraint->flag */ /* expand for UI */ #define CONSTRAINT_EXPAND 0x01 /* pre-check for illegal object name or bone name */ @@ -278,7 +295,7 @@ typedef struct bSizeLimitConstraint { /* to indicate that the owner's space should only be changed into ownspace, but not out of it */ #define CONSTRAINT_SPACEONCE 0x40 -/* bConstraint.ownspace/tarspace */ +/* bConstraint->ownspace/tarspace */ /* default for all - worldspace */ #define CONSTRAINT_SPACE_WORLD 0 /* for objects (relative to parent/without parent influence), for bones (along normals of bone, without parent/restposi) */ diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c index 0f94fa7195b..aca052a7694 100644 --- a/source/blender/python/api2_2x/Constraint.c +++ b/source/blender/python/api2_2x/Constraint.c @@ -25,7 +25,7 @@ * * This is a new part of Blender. * - * Contributor(s): Joseph Gilbert, Ken Hughes + * Contributor(s): Joseph Gilbert, Ken Hughes, Joshua Leung * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ @@ -134,6 +134,25 @@ enum constraint_constants { EXPP_CONSTR_SCRIPT, EXPP_CONSTR_PROPS, + EXPP_CONSTR_FROM, + EXPP_CONSTR_TO, + EXPP_CONSTR_EXPO, + EXPP_CONSTR_FROMMINX, + EXPP_CONSTR_FROMMAXX, + EXPP_CONSTR_FROMMINY, + EXPP_CONSTR_FROMMAXY, + EXPP_CONSTR_FROMMINZ, + EXPP_CONSTR_FROMMAXZ, + EXPP_CONSTR_TOMINX, + EXPP_CONSTR_TOMAXX, + EXPP_CONSTR_TOMINY, + EXPP_CONSTR_TOMAXY, + EXPP_CONSTR_TOMINZ, + EXPP_CONSTR_TOMAXZ, + EXPP_CONSTR_MAPX, + EXPP_CONSTR_MAPY, + EXPP_CONSTR_MAPZ, + EXPP_CONSTR_OWNSPACE, EXPP_CONSTR_TARSPACE, @@ -1397,6 +1416,147 @@ static int childof_setter( BPy_Constraint *self, int type, PyObject *value ) } } +static PyObject *transf_getter( BPy_Constraint * self, int type ) +{ + bTransformConstraint *con = (bTransformConstraint *)(self->con->data); + + switch( type ) { + case EXPP_CONSTR_TARGET: + return Object_CreatePyObject( con->tar ); + case EXPP_CONSTR_BONE: + return PyString_FromString( con->subtarget ); + case EXPP_CONSTR_FROM: + return PyInt_FromLong( (long)con->from ); + case EXPP_CONSTR_TO: + return PyInt_FromLong( (long)con->to ); + case EXPP_CONSTR_MAPX: + return PyInt_FromLong( (long)con->map[0] ); + case EXPP_CONSTR_MAPY: + return PyInt_FromLong( (long)con->map[1] ); + case EXPP_CONSTR_MAPZ: + return PyInt_FromLong( (long)con->map[2] ); + case EXPP_CONSTR_FROMMINX: + return PyFloat_FromDouble( (double)con->from_min[0] ); + case EXPP_CONSTR_FROMMAXX: + return PyFloat_FromDouble( (double)con->from_max[0] ); + case EXPP_CONSTR_FROMMINY: + return PyFloat_FromDouble( (double)con->from_min[1] ); + case EXPP_CONSTR_FROMMAXY: + return PyFloat_FromDouble( (double)con->from_max[1] ); + case EXPP_CONSTR_FROMMINZ: + return PyFloat_FromDouble( (double)con->from_min[2] ); + case EXPP_CONSTR_FROMMAXZ: + return PyFloat_FromDouble( (double)con->from_max[2] ); + case EXPP_CONSTR_TOMINX: + return PyFloat_FromDouble( (double)con->to_min[0] ); + case EXPP_CONSTR_TOMAXX: + return PyFloat_FromDouble( (double)con->to_max[0] ); + case EXPP_CONSTR_TOMINY: + return PyFloat_FromDouble( (double)con->to_min[1] ); + case EXPP_CONSTR_TOMAXY: + return PyFloat_FromDouble( (double)con->to_max[1] ); + case EXPP_CONSTR_TOMINZ: + return PyFloat_FromDouble( (double)con->to_min[2] ); + case EXPP_CONSTR_TOMAXZ: + return PyFloat_FromDouble( (double)con->to_max[2] ); + case EXPP_CONSTR_EXPO: + return PyBool_FromLong( (long)con->expo ); + default: + return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" ); + } +} + +static int transf_setter( BPy_Constraint *self, int type, PyObject *value ) +{ + bTransformConstraint *con = (bTransformConstraint *)(self->con->data); + float fmin, fmax, tmin, tmax; + + if (con->from == 2) { + fmin = 0.0001; + fmax = 1000.0; + } + else if (con->from == 1) { + fmin = -360.0; + fmax = 360.0; + } + else { + fmin = -1000.0; + fmax = 1000.0; + } + + if (con->to == 2) { + tmin = 0.0001; + tmax = 1000.0; + } + else if (con->to == 1) { + tmin = -360.0; + tmax = 360.0; + } + else { + tmin = -1000.0; + tmax = 1000.0; + } + + switch( type ) { + case EXPP_CONSTR_TARGET: { + Object *obj = (( BPy_Object * )value)->object; + if( !BPy_Object_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected BPy object argument" ); + con->tar = obj; + return 0; + } + case EXPP_CONSTR_BONE: { + char *name = PyString_AsString( value ); + if( !name ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected string arg" ); + + BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) ); + + return 0; + } + case EXPP_CONSTR_FROM: + return EXPP_setIValueClamped( value, &con->from, 0, 3, 'h' ); + case EXPP_CONSTR_TO: + return EXPP_setIValueClamped( value, &con->to, 0, 3, 'h' ); + case EXPP_CONSTR_MAPX: + return EXPP_setIValueClamped( value, &con->map[0], 0, 3, 'h' ); + case EXPP_CONSTR_MAPY: + return EXPP_setIValueClamped( value, &con->map[1], 0, 3, 'h' ); + case EXPP_CONSTR_MAPZ: + return EXPP_setIValueClamped( value, &con->map[2], 0, 3, 'h' ); + case EXPP_CONSTR_FROMMINX: + return EXPP_setFloatClamped( value, &con->from_min[0], fmin, fmax ); + case EXPP_CONSTR_FROMMAXX: + return EXPP_setFloatClamped( value, &con->from_max[0], fmin, fmax ); + case EXPP_CONSTR_FROMMINY: + return EXPP_setFloatClamped( value, &con->from_min[1], fmin, fmax ); + case EXPP_CONSTR_FROMMAXY: + return EXPP_setFloatClamped( value, &con->from_max[1], fmin, fmax ); + case EXPP_CONSTR_FROMMINZ: + return EXPP_setFloatClamped( value, &con->from_min[2], fmin, fmax ); + case EXPP_CONSTR_FROMMAXZ: + return EXPP_setFloatClamped( value, &con->from_max[2], fmin, fmax ); + case EXPP_CONSTR_TOMINX: + return EXPP_setFloatClamped( value, &con->to_min[0], tmin, tmax ); + case EXPP_CONSTR_TOMAXX: + return EXPP_setFloatClamped( value, &con->to_max[0], tmin, tmax ); + case EXPP_CONSTR_TOMINY: + return EXPP_setFloatClamped( value, &con->to_min[1], tmin, tmax ); + case EXPP_CONSTR_TOMAXY: + return EXPP_setFloatClamped( value, &con->to_max[1], tmin, tmax ); + case EXPP_CONSTR_TOMINZ: + return EXPP_setFloatClamped( value, &con->to_min[2], tmin, tmax ); + case EXPP_CONSTR_TOMAXZ: + return EXPP_setFloatClamped( value, &con->to_max[2], tmin, tmax ); + case EXPP_CONSTR_EXPO: + return EXPP_setBitfield( value, &con->expo, 1, 'h' ); + default: + return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); + } +} + /* * get data from a constraint */ @@ -1451,6 +1611,8 @@ static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key ) return script_getter( self, setting ); case CONSTRAINT_TYPE_CHILDOF: return childof_getter( self, setting ); + case CONSTRAINT_TYPE_TRANSFORM: + return transf_getter( self, setting ); default: return EXPP_ReturnPyObjError( PyExc_KeyError, "unknown constraint type" ); @@ -1522,6 +1684,9 @@ static int Constraint_setData( BPy_Constraint * self, PyObject * key, case CONSTRAINT_TYPE_CHILDOF: result = childof_setter( self, key_int, arg); break; + case CONSTRAINT_TYPE_TRANSFORM: + result = transf_setter( self, key_int, arg); + break; case CONSTRAINT_TYPE_NULL: return EXPP_ReturnIntError( PyExc_KeyError, "key not found" ); default: @@ -1995,6 +2160,8 @@ static PyObject *M_Constraint_TypeDict( void ) PyInt_FromLong( CONSTRAINT_TYPE_PYTHON ) ); PyConstant_Insert( d, "CHILDOF", PyInt_FromLong( CONSTRAINT_TYPE_CHILDOF ) ); + PyConstant_Insert( d, "TRANSFORM", + PyInt_FromLong( CONSTRAINT_TYPE_TRANSFORM ) ); } return S; } @@ -2222,6 +2389,50 @@ static PyObject *M_Constraint_SettingsDict( void ) PyConstant_Insert( d, "PROPERTIES", PyInt_FromLong( EXPP_CONSTR_PROPS ) ); + PyConstant_Insert( d, "FROM", + PyInt_FromLong( EXPP_CONSTR_FROM ) ); + PyConstant_Insert( d, "TO", + PyInt_FromLong( EXPP_CONSTR_TO ) ); + PyConstant_Insert( d, "EXTRAPOLATE", + PyInt_FromLong( EXPP_CONSTR_EXPO ) ); + PyConstant_Insert( d, "MAPX", + PyInt_FromLong( EXPP_CONSTR_MAPX ) ); + PyConstant_Insert( d, "MAPY", + PyInt_FromLong( EXPP_CONSTR_MAPY ) ); + PyConstant_Insert( d, "MAPZ", + PyInt_FromLong( EXPP_CONSTR_MAPZ ) ); + PyConstant_Insert( d, "FROM_MINX", + PyInt_FromLong( EXPP_CONSTR_FROMMINX ) ); + PyConstant_Insert( d, "FROM_MAXX", + PyInt_FromLong( EXPP_CONSTR_FROMMAXX ) ); + PyConstant_Insert( d, "FROM_MINY", + PyInt_FromLong( EXPP_CONSTR_FROMMINY ) ); + PyConstant_Insert( d, "FROM_MAXY", + PyInt_FromLong( EXPP_CONSTR_FROMMAXY ) ); + PyConstant_Insert( d, "FROM_MINZ", + PyInt_FromLong( EXPP_CONSTR_FROMMINZ ) ); + PyConstant_Insert( d, "FROM_MAXZ", + PyInt_FromLong( EXPP_CONSTR_FROMMAXZ ) ); + PyConstant_Insert( d, "TO_MINX", + PyInt_FromLong( EXPP_CONSTR_TOMINX ) ); + PyConstant_Insert( d, "TO_MAXX", + PyInt_FromLong( EXPP_CONSTR_TOMAXX ) ); + PyConstant_Insert( d, "TO_MINY", + PyInt_FromLong( EXPP_CONSTR_TOMINY ) ); + PyConstant_Insert( d, "TO_MAXY", + PyInt_FromLong( EXPP_CONSTR_TOMAXY ) ); + PyConstant_Insert( d, "TO_MINZ", + PyInt_FromLong( EXPP_CONSTR_TOMINZ ) ); + PyConstant_Insert( d, "TO_MAXZ", + PyInt_FromLong( EXPP_CONSTR_TOMAXZ ) ); + + PyConstant_Insert( d, "LOC", + PyInt_FromLong( 0 ) ); + PyConstant_Insert( d, "ROT", + PyInt_FromLong( 1 ) ); + PyConstant_Insert( d, "SCALE", + PyInt_FromLong( 2 ) ); + PyConstant_Insert( d, "CONSTR_RB_TYPE", PyInt_FromLong( EXPP_CONSTR_RB_TYPE ) ); PyConstant_Insert( d, "CONSTR_RB_BALL", diff --git a/source/blender/python/api2_2x/doc/Constraint.py b/source/blender/python/api2_2x/doc/Constraint.py index 122756a9ae2..1d52c755d33 100644 --- a/source/blender/python/api2_2x/doc/Constraint.py +++ b/source/blender/python/api2_2x/doc/Constraint.py @@ -32,7 +32,7 @@ Or to print all the constraints attached to each bone in a pose:: for comparison with L{Constraint.type}. Values are TRACKTO, IKSOLVER, FOLLOWPATH, COPYROT, COPYLOC, COPYSIZE, ACTION, LOCKTRACK, STRETCHTO, FLOOR, LIMITLOC, LIMITROT, LIMITSIZE, CLAMPTO, - PYTHON, CHILDOF, NULL + PYTHON, CHILDOF, TRANSFORM, NULL @type Settings: readonly dictionary @var Settings: Constant dict used for changing constraint settings. @@ -120,6 +120,20 @@ Or to print all the constraints attached to each bone in a pose:: - Used by Child Of (CHILDOF) constraint: - COPY (bitfield): any combination of PARLOCX, PARLOCY, PARLOCZ, PARROTX, PARROTY, PARROTZ, PARSIZEX, PARSIZEY, PARSIZEZ. + - Used by Transformation (TRANSFORM) constraint: + - FROM (int): values are LOC, ROT, SCALE + - TO (int): values are LOC, ROT, SCALE + - MAPX, MAPY, MAPZ (int): values are LOC, ROT, SCALE + - EXTRAPOLATE (bool) + - FROM_MINX, FROM_MINY, FROM_MINZ, FROM_MAXX, + FROM_MAXY, FROM_MAXZ (float): + If FROM==LOC, then is clamped to [-1000.0, 1000.0] + If FROM==ROT, then is clamped to [-360.0, 360.0] + If FROM==SCALE, then is clamped to [0.0001, 1000.0] + - TO_MINX, TO_MINY, TO_MINZ, TO_MAXX, TO_MAXY, TO_MAXZ (float): + If TO==LOC, then is clamped to [-1000.0, 1000.0] + If TO==ROT, then is clamped to [-360.0, 360.0] + If TO==SCALE, then is clamped to [0.0001, 1000.0] """ diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 0f7aee08afc..d2ca53743f7 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -329,105 +329,70 @@ void get_constraint_typestring (char *str, void *con_v) { bConstraint *con= con_v; - switch (con->type){ + switch (con->type) { case CONSTRAINT_TYPE_PYTHON: strcpy(str, "Script"); return; case CONSTRAINT_TYPE_CHILDOF: - strcpy (str, "Child Of"); + strcpy(str, "Child Of"); return; case CONSTRAINT_TYPE_NULL: - strcpy (str, "Null"); + strcpy(str, "Null"); return; case CONSTRAINT_TYPE_TRACKTO: - strcpy (str, "Track To"); + strcpy(str, "Track To"); return; case CONSTRAINT_TYPE_MINMAX: - strcpy (str, "Floor"); + strcpy(str, "Floor"); return; case CONSTRAINT_TYPE_KINEMATIC: - strcpy (str, "IK Solver"); + strcpy(str, "IK Solver"); return; case CONSTRAINT_TYPE_ROTLIKE: - strcpy (str, "Copy Rotation"); + strcpy(str, "Copy Rotation"); return; case CONSTRAINT_TYPE_LOCLIKE: - strcpy (str, "Copy Location"); + strcpy(str, "Copy Location"); return; case CONSTRAINT_TYPE_SIZELIKE: - strcpy (str, "Copy Scale"); + strcpy(str, "Copy Scale"); return; case CONSTRAINT_TYPE_ACTION: - strcpy (str, "Action"); + strcpy(str, "Action"); return; case CONSTRAINT_TYPE_LOCKTRACK: - strcpy (str, "Locked Track"); + strcpy(str, "Locked Track"); return; case CONSTRAINT_TYPE_FOLLOWPATH: - strcpy (str, "Follow Path"); + strcpy(str, "Follow Path"); return; case CONSTRAINT_TYPE_STRETCHTO: - strcpy (str, "Stretch To"); + strcpy(str, "Stretch To"); return; case CONSTRAINT_TYPE_LOCLIMIT: - strcpy (str, "Limit Location"); + strcpy(str, "Limit Location"); return; case CONSTRAINT_TYPE_ROTLIMIT: - strcpy (str, "Limit Rotation"); + strcpy(str, "Limit Rotation"); return; case CONSTRAINT_TYPE_SIZELIMIT: - strcpy (str, "Limit Scale"); + strcpy(str, "Limit Scale"); return; case CONSTRAINT_TYPE_RIGIDBODYJOINT: - strcpy (str, "Rigid Body"); + strcpy(str, "Rigid Body"); return; case CONSTRAINT_TYPE_CLAMPTO: - strcpy (str, "Clamp To"); + strcpy(str, "Clamp To"); return; + case CONSTRAINT_TYPE_TRANSFORM: + strcpy(str, "Transformation"); + break; default: strcpy (str, "Unknown"); return; } } -static int get_constraint_col(bConstraint *con) -{ - switch (con->type) { - case CONSTRAINT_TYPE_NULL: - return TH_BUT_NEUTRAL; - case CONSTRAINT_TYPE_KINEMATIC: - return TH_BUT_SETTING2; - case CONSTRAINT_TYPE_TRACKTO: - return TH_BUT_SETTING; - case CONSTRAINT_TYPE_ROTLIKE: - return TH_BUT_SETTING1; - case CONSTRAINT_TYPE_LOCLIKE: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_MINMAX: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_SIZELIKE: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_ACTION: - return TH_BUT_ACTION; - case CONSTRAINT_TYPE_LOCKTRACK: - return TH_BUT_SETTING; - case CONSTRAINT_TYPE_FOLLOWPATH: - return TH_BUT_SETTING2; - case CONSTRAINT_TYPE_STRETCHTO: - return TH_BUT_SETTING; - case CONSTRAINT_TYPE_LOCLIMIT: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_ROTLIMIT: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_SIZELIMIT: - return TH_BUT_POPUP; - case CONSTRAINT_TYPE_RIGIDBODYJOINT: - return TH_BUT_SETTING; - default: - return TH_REDALERT; - } -} - void const_moveUp(void *ob_v, void *con_v) { bConstraint *con, *constr= con_v; @@ -602,7 +567,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s char typestr[64], *subtarget; short height, width = 265; short is_armature_target, is_armature_owner; - int curCol, rb_col; + int rb_col; target= get_constraint_target(con, &subtarget); is_armature_target= (target && target->type==OB_ARMATURE); @@ -613,8 +578,6 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s get_constraint_typestring(typestr, con); - curCol = get_constraint_col(con); - /* Draw constraint header */ uiBlockSetEmboss(block, UI_EMBOSSN); @@ -635,12 +598,8 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiButSetFunc(but, constraint_moveDown, ob, con); if (con->flag & CONSTRAINT_EXPAND) { - if (con->flag & CONSTRAINT_DISABLE) { - BIF_ThemeColor(TH_REDALERT); + if (con->flag & CONSTRAINT_DISABLE) uiBlockSetCol(block, TH_REDALERT); - } - else - BIF_ThemeColor(curCol); uiBlockSetEmboss(block, UI_EMBOSS); @@ -652,12 +611,8 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s else { uiBlockSetEmboss(block, UI_EMBOSSN); - if (con->flag & CONSTRAINT_DISABLE) { + if (con->flag & CONSTRAINT_DISABLE) uiBlockSetCol(block, TH_REDALERT); - BIF_ThemeColor(TH_REDALERT); - } - else - BIF_ThemeColor(curCol); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, *xco+10, *yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); @@ -1095,13 +1050,13 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s bLockTrackConstraint *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 */ 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) { 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); @@ -1135,21 +1090,21 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s case CONSTRAINT_TYPE_FOLLOWPATH: { bFollowPathConstraint *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 Curve Follow toggle */ but=uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "CurveFollow", *xco+39, *yco-44, 100, 18, &data->followflag, 0, 24, 0, 0, "Object will follow the heading and banking of the curve"); - + /* Draw Offset number button */ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Offset:", *xco+155, *yco-44, 100, 18, &data->offset, -MAXFRAMEF, MAXFRAMEF, 100.0, 0.0, "Offset from the position corresponding to the time frame"); - + uiBlockBeginAlign(block); uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Fw:", *xco+12, *yco-64, 27, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); @@ -1455,11 +1410,127 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s uiBlockEndAlign(block); } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = con->data; + float fmin, fmax, tmin, tmax; + + height = 178; + uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); + + /* Draw target parameters */ + 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 to use as Parent"); + + if (is_armature_target) { + but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent"); + uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar); + } + else { + strcpy(data->subtarget, ""); + } + + uiBlockEndAlign(block); + + /* Extrapolate Ranges? */ + uiDefButBitC(block, TOG, 1, B_CONSTRAINT_TEST, "Extrapolate", *xco, *yco-42,80,19, &data->expo, 0, 0, 0, 0, "Extrapolate ranges"); + + /* Draw options for source motion */ + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Source:", *xco-10, *yco-62, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + /* draw Loc/Rot/Size toggles */ + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco-5, *yco-82, 45, 18, &data->from, 12.0, 0, 0, 0, "Use Location transform channels from Target"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+40, *yco-82, 45, 18, &data->from, 12.0, 1, 0, 0, "Use Rotation transform channels from Target"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+85, *yco-82, 45, 18, &data->from, 12.0, 2, 0, 0, "Use Scale transform channels from Target"); + uiBlockEndAlign(block); + + /* Draw Pairs of Axis: Min/Max Value*/ + if (data->from == 2) { + fmin= 0.0001; + fmax= 1000.0; + } + else if (data->from == 1) { + fmin= -360.0; + fmax= 360.0; + } + else { + fmin = -1000.0; + fmax= 1000.0; + } + + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "X:", *xco-10, *yco-107, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-107, 55, 18, &data->from_min[0], fmin, fmax, 0, 0, "Bottom of range of x-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-107, 55, 18, &data->from_max[0], fmin, fmax, 0, 0, "Top of range of x-axis source motion for source->target mapping"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Y:", *xco-10, *yco-127, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-127, 55, 18, &data->from_min[1], fmin, fmax, 0, 0, "Bottom of range of y-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-127, 55, 18, &data->from_max[1], fmin, fmax, 0, 0, "Top of range of y-axis source motion for source->target mapping"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Z:", *xco-10, *yco-147, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-147, 55, 18, &data->from_min[2], fmin, fmax, 0, 0, "Bottom of range of z-axis source motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-147, 55, 18, &data->from_max[2], fmin, fmax, 0, 0, "Top of range of z-axis source motion for source->target mapping"); + uiBlockEndAlign(block); + + + /* Draw options for target motion */ + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Destination:", *xco+150, *yco-62, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); + + /* draw Loc/Rot/Size toggles */ + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco+150, *yco-82, 45, 18, &data->to, 12.0, 0, 0, 0, "Use as Location transform"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+195, *yco-82, 45, 18, &data->to, 12.0, 1, 0, 0, "Use as Rotation transform"); + uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+245, *yco-82, 45, 18, &data->to, 12.0, 2, 0, 0, "Use as Scale transform"); + uiBlockEndAlign(block); + + /* Draw Pairs of Source-Axis: Min/Max Value*/ + if (data->to == 2) { + tmin= 0.0001; + tmax= 1000.0; + } + else if (data->to == 1) { + tmin= -360.0; + tmax= 360.0; + } + else { + tmin = -1000.0; + tmax= 1000.0; + } + + uiBlockBeginAlign(block); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->X%x0|Y->X%x1|Z->X%x2", *xco+150, *yco-107, 40, 18, &data->map[0], 0, 24, 0, 0, "Specify which source axis the x-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-107, 50, 18, &data->to_min[0], tmin, tmax, 0, 0, "Bottom of range of x-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-107, 50, 18, &data->to_max[0], tmin, tmax, 0, 0, "Top of range of x-axis destination motion for source->target mapping"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Y%x0|Y->Y%x1|Z->Y%x2", *xco+150, *yco-127, 40, 18, &data->map[1], 0, 24, 0, 0, "Specify which source axis the y-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-127, 50, 18, &data->to_min[1], tmin, tmax, 0, 0, "Bottom of range of y-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-127, 50, 18, &data->to_max[1], tmin, tmax, 0, 0, "Top of range of y-axis destination motion for source->target mapping"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Z%x0|Y->Z%x1|Z->Z%x2", *xco+150, *yco-147, 40, 18, &data->map[2], 0, 24, 0, 0, "Specify which source axis the z-axis destination uses"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-147, 50, 18, &data->to_min[2], tmin, tmax, 0, 0, "Bottom of range of z-axis destination motion for source->target mapping"); + uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-147, 50, 18, &data->to_max[2], tmin, tmax, 0, 0, "Top of range of z-axis destination motion for source->target mapping"); + uiBlockEndAlign(block); + + /* constraint space settings */ + draw_constraint_spaceselect(block, con, *xco, *yco-170, is_armature_owner, is_armature_target); + } + break; case CONSTRAINT_TYPE_NULL: { height = 17; uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); - } break; default: @@ -1499,6 +1570,7 @@ static uiBlock *add_constraintmenu(void *arg_unused) block= uiNewBlock(&curarea->uiblocks, "add_constraintmenu", UI_EMBOSSP, UI_HELV, curarea->win); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CHILDOF, "Child Of", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_TRANSFORM, "Transformation", 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, ""); @@ -1518,10 +1590,10 @@ 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, ""); + uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CLAMPTO, "Clamp To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_STRETCHTO, "Stretch To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefBut(block, BUTM, B_CONSTRAINT_ADD_RIGIDBODYJOINT, "Rigid Body Joint", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");//rcruiz @@ -1735,6 +1807,14 @@ void do_constraintbuts(unsigned short event) BIF_undo_push("Add constraint"); } break; + case B_CONSTRAINT_ADD_TRANSFORM: + { + con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM); + 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 db1ee37405f..4ef1b4e961a 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -583,6 +583,24 @@ static void test_constraints (Object *owner, const char* substring) } } break; + case CONSTRAINT_TYPE_TRANSFORM: + { + bTransformConstraint *data = curcon->data; + + if (!exist_object(data->tar)){ + data->tar = NULL; + curcon->flag |= CONSTRAINT_DISABLE; + break; + } + + if ( (data->tar == owner) && + (!get_named_bone(get_armature(owner), + data->subtarget))) { + curcon->flag |= CONSTRAINT_DISABLE; + break; + } + } + break; } } } @@ -671,21 +689,21 @@ void add_constraint(int only_IK) else { if(pchanact) { if(pchansel) - nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|%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|%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|%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|%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|%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|%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|%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|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|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Script%x18"); } else { if(obsel && obsel->type==OB_CURVE) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|%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|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|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Script%x18"); else if(obsel) - nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|%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|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|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Script%x18"); else - nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|%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|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|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Script%x18"); } } @@ -773,7 +791,7 @@ void add_constraint(int only_IK) } } else if (nr==19) { - con= add_new_constraint(CONSTRAINT_TYPE_CHILDOF); + con = add_new_constraint(CONSTRAINT_TYPE_CHILDOF); /* if this constraint is being added to a posechannel, make sure * the constraint gets evaluated in pose-space @@ -783,6 +801,7 @@ void add_constraint(int only_IK) con->flag |= CONSTRAINT_SPACEONCE; } } + else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM); if (con==NULL) return; /* paranoia */