Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_constraints.c
| Show First 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | |||||
| * Generic callback for constant spatial constraints applied to linear motion | * Generic callback for constant spatial constraints applied to linear motion | ||||
| * | * | ||||
| * The IN vector in projected into the constrained space and then further | * The IN vector in projected into the constrained space and then further | ||||
| * projected along the view vector. | * projected along the view vector. | ||||
| * (in perspective mode, the view vector is relative to the position on screen) | * (in perspective mode, the view vector is relative to the position on screen) | ||||
| * | * | ||||
| */ | */ | ||||
| static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3]) | static void applyAxisConstraintVec( | ||||
| TransInfo *t, TransHandle *UNUSED(th), TransData *td, const float in[3], float out[3], float pvec[3]) | |||||
| { | { | ||||
| copy_v3_v3(out, in); | copy_v3_v3(out, in); | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!td && t->con.mode & CON_APPLY) { | ||||
| mul_m3_v3(t->con.pmtx, out); | mul_m3_v3(t->con.pmtx, out); | ||||
| // With snap, a projection is alright, no need to correct for view alignment | // With snap, a projection is alright, no need to correct for view alignment | ||||
| if (!(!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t))) { | if (!(!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t))) { | ||||
| Show All 30 Lines | |||||
| * At first, the following is applied to the first data in the array | * At first, the following is applied to the first data in the array | ||||
| * The IN vector in projected into the constrained space and then further | * The IN vector in projected into the constrained space and then further | ||||
| * projected along the view vector. | * projected along the view vector. | ||||
| * (in perspective mode, the view vector is relative to the position on screen) | * (in perspective mode, the view vector is relative to the position on screen) | ||||
| * | * | ||||
| * Further down, that vector is mapped to each data's space. | * Further down, that vector is mapped to each data's space. | ||||
| */ | */ | ||||
| static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3]) | static void applyObjectConstraintVec( | ||||
| TransInfo *t, TransHandle *th, TransData *td, const float in[3], float out[3], float pvec[3]) | |||||
| { | { | ||||
| copy_v3_v3(out, in); | copy_v3_v3(out, in); | ||||
| if (t->con.mode & CON_APPLY) { | if (t->con.mode & CON_APPLY) { | ||||
| if (!td) { | if (!td) { | ||||
| mul_m3_v3(t->con.pmtx, out); | mul_m3_v3(t->con.pmtx, out); | ||||
| const int dims = getConstraintSpaceDimension(t); | const int dims = getConstraintSpaceDimension(t); | ||||
| if (dims == 2) { | if (dims == 2) { | ||||
| Show All 31 Lines | else { | ||||
| out[1] = in[i++]; | out[1] = in[i++]; | ||||
| } | } | ||||
| if (t->con.mode & CON_AXIS2) { | if (t->con.mode & CON_AXIS2) { | ||||
| out[2] = in[i++]; | out[2] = in[i++]; | ||||
| } | } | ||||
| mul_m3_v3(td->axismtx, out); | mul_m3_v3(td->axismtx, out); | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_v3(t->obedit_mat, out); | mul_m3_v3(th->obedit_mat, out); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Generic callback for constant spatial constraints applied to resize motion | * Generic callback for constant spatial constraints applied to resize motion | ||||
| */ | */ | ||||
| static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) | static void applyAxisConstraintSize( | ||||
| TransInfo *t, TransHandle *UNUSED(th), TransData *td, float smat[3][3]) | |||||
| { | { | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!td && t->con.mode & CON_APPLY) { | ||||
| float tmat[3][3]; | float tmat[3][3]; | ||||
| if (!(t->con.mode & CON_AXIS0)) { | if (!(t->con.mode & CON_AXIS0)) { | ||||
| smat[0][0] = 1.0f; | smat[0][0] = 1.0f; | ||||
| } | } | ||||
| if (!(t->con.mode & CON_AXIS1)) { | if (!(t->con.mode & CON_AXIS1)) { | ||||
| smat[1][1] = 1.0f; | smat[1][1] = 1.0f; | ||||
| } | } | ||||
| if (!(t->con.mode & CON_AXIS2)) { | if (!(t->con.mode & CON_AXIS2)) { | ||||
| smat[2][2] = 1.0f; | smat[2][2] = 1.0f; | ||||
| } | } | ||||
| mul_m3_m3m3(tmat, smat, t->con.imtx); | mul_m3_m3m3(tmat, smat, t->con.imtx); | ||||
| mul_m3_m3m3(smat, t->con.mtx, tmat); | mul_m3_m3m3(smat, t->con.mtx, tmat); | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Callback for object based spatial constraints applied to resize motion | * Callback for object based spatial constraints applied to resize motion | ||||
| */ | */ | ||||
| static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) | static void applyObjectConstraintSize( | ||||
| TransInfo *t, TransHandle *th, TransData *td, float smat[3][3]) | |||||
| { | { | ||||
| if (td && t->con.mode & CON_APPLY) { | if (td && t->con.mode & CON_APPLY) { | ||||
| float tmat[3][3]; | float tmat[3][3]; | ||||
| float imat[3][3]; | float imat[3][3]; | ||||
| invert_m3_m3(imat, td->axismtx); | invert_m3_m3(imat, td->axismtx); | ||||
| if (!(t->con.mode & CON_AXIS0)) { | if (!(t->con.mode & CON_AXIS0)) { | ||||
| smat[0][0] = 1.0f; | smat[0][0] = 1.0f; | ||||
| } | } | ||||
| if (!(t->con.mode & CON_AXIS1)) { | if (!(t->con.mode & CON_AXIS1)) { | ||||
| smat[1][1] = 1.0f; | smat[1][1] = 1.0f; | ||||
| } | } | ||||
| if (!(t->con.mode & CON_AXIS2)) { | if (!(t->con.mode & CON_AXIS2)) { | ||||
| smat[2][2] = 1.0f; | smat[2][2] = 1.0f; | ||||
| } | } | ||||
| mul_m3_m3m3(tmat, smat, imat); | mul_m3_m3m3(tmat, smat, imat); | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_m3m3(smat, t->obedit_mat, smat); | mul_m3_m3m3(smat, th->obedit_mat, smat); | ||||
| } | } | ||||
| mul_m3_m3m3(smat, td->axismtx, tmat); | mul_m3_m3m3(smat, td->axismtx, tmat); | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Generic callback for constant spatial constraints applied to rotations | * Generic callback for constant spatial constraints applied to rotations | ||||
| * | * | ||||
| * The rotation axis is copied into VEC. | * The rotation axis is copied into VEC. | ||||
| * | * | ||||
| * In the case of single axis constraints, the rotation axis is directly the one constrained to. | * In the case of single axis constraints, the rotation axis is directly the one constrained to. | ||||
| * For planar constraints (2 axis), the rotation axis is the normal of the plane. | * For planar constraints (2 axis), the rotation axis is the normal of the plane. | ||||
| * | * | ||||
| * The following only applies when CON_NOFLIP is not set. | * The following only applies when CON_NOFLIP is not set. | ||||
| * The vector is then modified to always point away from the screen (in global space) | * The vector is then modified to always point away from the screen (in global space) | ||||
| * This insures that the rotation is always logically following the mouse. | * This insures that the rotation is always logically following the mouse. | ||||
| * (ie: not doing counterclockwise rotations when the mouse moves clockwise). | * (ie: not doing counterclockwise rotations when the mouse moves clockwise). | ||||
| */ | */ | ||||
| static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle) | static void applyAxisConstraintRot(TransInfo *t, TransHandle *UNUSED(th), TransData *td, float vec[3], float *angle) | ||||
| { | { | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!td && t->con.mode & CON_APPLY) { | ||||
| int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); | int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); | ||||
| switch (mode) { | switch (mode) { | ||||
| case CON_AXIS0: | case CON_AXIS0: | ||||
| case (CON_AXIS1 | CON_AXIS2): | case (CON_AXIS1 | CON_AXIS2): | ||||
| copy_v3_v3(vec, t->con.mtx[0]); | copy_v3_v3(vec, t->con.mtx[0]); | ||||
| Show All 25 Lines | |||||
| * For planar constraints (2 axis), the rotation axis is the normal of the plane. | * For planar constraints (2 axis), the rotation axis is the normal of the plane. | ||||
| * | * | ||||
| * The following only applies when CON_NOFLIP is not set. | * The following only applies when CON_NOFLIP is not set. | ||||
| * The vector is then modified to always point away from the screen (in global space) | * The vector is then modified to always point away from the screen (in global space) | ||||
| * This insures that the rotation is always logically following the mouse. | * This insures that the rotation is always logically following the mouse. | ||||
| * (ie: not doing counterclockwise rotations when the mouse moves clockwise). | * (ie: not doing counterclockwise rotations when the mouse moves clockwise). | ||||
| */ | */ | ||||
| static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle) | static void applyObjectConstraintRot( | ||||
| TransInfo *t, TransHandle *th, TransData *td, float vec[3], float *angle) | |||||
| { | { | ||||
| if (t->con.mode & CON_APPLY) { | if (t->con.mode & CON_APPLY) { | ||||
| int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); | int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); | ||||
| float tmp_axismtx[3][3]; | float tmp_axismtx[3][3]; | ||||
| float (*axismtx)[3]; | float (*axismtx)[3]; | ||||
| /* on setup call, use first object */ | /* on setup call, use first object */ | ||||
| if (td == NULL) { | if (td == NULL) { | ||||
| td = t->data; | td = th->data; | ||||
| } | } | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx); | mul_m3_m3m3(tmp_axismtx, th->obedit_mat, td->axismtx); | ||||
| axismtx = tmp_axismtx; | axismtx = tmp_axismtx; | ||||
| } | } | ||||
| else { | else { | ||||
| axismtx = td->axismtx; | axismtx = td->axismtx; | ||||
| } | } | ||||
| switch (mode) { | switch (mode) { | ||||
| case CON_AXIS0: | case CON_AXIS0: | ||||
| Show All 33 Lines | void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) | ||||
| t->con.applySize = applyAxisConstraintSize; | t->con.applySize = applyAxisConstraintSize; | ||||
| t->con.applyRot = applyAxisConstraintRot; | t->con.applyRot = applyAxisConstraintRot; | ||||
| t->redraw = TREDRAW_HARD; | t->redraw = TREDRAW_HARD; | ||||
| } | } | ||||
| /* applies individual td->axismtx constraints */ | /* applies individual td->axismtx constraints */ | ||||
| void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) | void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) | ||||
| { | { | ||||
| if (t->total == 1) { | TransHandle *th = t->thand; | ||||
| if (t->total_all_handle == 1) { | |||||
| float axismtx[3][3]; | float axismtx[3][3]; | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_m3m3(axismtx, t->obedit_mat, t->data->axismtx); | mul_m3_m3m3(axismtx, th->obedit_mat, th->data->axismtx); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_m3_m3(axismtx, t->data->axismtx); | copy_m3_m3(axismtx, th->data->axismtx); | ||||
| } | } | ||||
| setConstraint(t, axismtx, mode, text); | setConstraint(t, axismtx, mode, text); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); | BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); | ||||
| copy_m3_m3(t->con.mtx, t->data->axismtx); | copy_m3_m3(t->con.mtx, th->data->axismtx); | ||||
| t->con.mode = mode; | t->con.mode = mode; | ||||
| getConstraintMatrix(t); | getConstraintMatrix(t); | ||||
| startConstraint(t); | startConstraint(t); | ||||
| t->con.drawExtra = drawObjectConstraint; | t->con.drawExtra = drawObjectConstraint; | ||||
| t->con.applyVec = applyObjectConstraintVec; | t->con.applyVec = applyObjectConstraintVec; | ||||
| t->con.applySize = applyObjectConstraintSize; | t->con.applySize = applyObjectConstraintSize; | ||||
| t->con.applyRot = applyObjectConstraintRot; | t->con.applyRot = applyObjectConstraintRot; | ||||
| t->redraw = TREDRAW_HARD; | t->redraw = TREDRAW_HARD; | ||||
| } | } | ||||
| } | } | ||||
| void setLocalConstraint(TransInfo *t, int mode, const char text[]) | void setLocalConstraint(TransInfo *t, int mode, const char text[]) | ||||
| { | { | ||||
| /* edit-mode now allows local transforms too */ | /* edit-mode now allows local transforms too */ | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| setConstraint(t, t->obedit_mat, mode, text); | /* Use the active (first) edit object. */ | ||||
| TransHandle *th = t->thand; | |||||
| setConstraint(t, th->obedit_mat, mode, text); | |||||
| } | } | ||||
| else { | else { | ||||
| setAxisMatrixConstraint(t, mode, text); | setAxisMatrixConstraint(t, mode, text); | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Set the constraint according to the user defined orientation | * Set the constraint according to the user defined orientation | ||||
| ▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| /* Draw the first one lighter because that's the one who controls the others. | /* Draw the first one lighter because that's the one who controls the others. | ||||
| * Meaning the transformation is projected on that one and just copied on the others | * Meaning the transformation is projected on that one and just copied on the others | ||||
| * constraint space. | * constraint space. | ||||
| * In a nutshell, the object with light axis is controlled by the user and the others follow. | * In a nutshell, the object with light axis is controlled by the user and the others follow. | ||||
| * Without drawing the first light, users have little clue what they are doing. | * Without drawing the first light, users have little clue what they are doing. | ||||
| */ | */ | ||||
| short options = DRAWLIGHT; | short options = DRAWLIGHT; | ||||
| TransData *td = t->data; | |||||
| int i; | int i; | ||||
| float tmp_axismtx[3][3]; | float tmp_axismtx[3][3]; | ||||
| for (i = 0; i < t->total; i++, td++) { | FOREACH_THAND (t, th) { | ||||
| TransData *td = th->data; | |||||
| for (i = 0; i < th->total; i++, td++) { | |||||
| float co[3]; | float co[3]; | ||||
| float (*axismtx)[3]; | float (*axismtx)[3]; | ||||
| if (t->flag & T_PROP_EDIT) { | if (t->flag & T_PROP_EDIT) { | ||||
| /* we're sorted, so skip the rest */ | /* we're sorted, so skip the rest */ | ||||
| if (td->factor == 0.0f) { | if (td->factor == 0.0f) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (t->options & CTX_GPENCIL_STROKES) { | if (t->options & CTX_GPENCIL_STROKES) { | ||||
| /* only draw a constraint line for one point, otherwise we can't see anything */ | /* only draw a constraint line for one point, otherwise we can't see anything */ | ||||
| if ((options & DRAWLIGHT) == 0) { | if ((options & DRAWLIGHT) == 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (t->flag & T_OBJECT) { | if (t->flag & T_OBJECT) { | ||||
| copy_v3_v3(co, td->ob->obmat[3]); | copy_v3_v3(co, td->ob->obmat[3]); | ||||
| axismtx = td->axismtx; | axismtx = td->axismtx; | ||||
| } | } | ||||
| else if (t->flag & T_EDIT) { | else if (t->flag & T_EDIT) { | ||||
| mul_v3_m4v3(co, t->obedit->obmat, td->center); | mul_v3_m4v3(co, th->obedit->obmat, td->center); | ||||
| mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx); | mul_m3_m3m3(tmp_axismtx, th->obedit_mat, td->axismtx); | ||||
| axismtx = tmp_axismtx; | axismtx = tmp_axismtx; | ||||
| } | } | ||||
| else if (t->flag & T_POSE) { | else if (t->flag & T_POSE) { | ||||
| mul_v3_m4v3(co, t->poseobj->obmat, td->center); | mul_v3_m4v3(co, th->poseobj->obmat, td->center); | ||||
| axismtx = td->axismtx; | axismtx = td->axismtx; | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(co, td->center); | copy_v3_v3(co, td->center); | ||||
| axismtx = td->axismtx; | axismtx = td->axismtx; | ||||
| } | } | ||||
| if (t->con.mode & CON_AXIS0) { | if (t->con.mode & CON_AXIS0) { | ||||
| drawLine(t, co, axismtx[0], 'X', options); | drawLine(t, co, axismtx[0], 'X', options); | ||||
| } | } | ||||
| if (t->con.mode & CON_AXIS1) { | if (t->con.mode & CON_AXIS1) { | ||||
| drawLine(t, co, axismtx[1], 'Y', options); | drawLine(t, co, axismtx[1], 'Y', options); | ||||
| } | } | ||||
| if (t->con.mode & CON_AXIS2) { | if (t->con.mode & CON_AXIS2) { | ||||
| drawLine(t, co, axismtx[2], 'Z', options); | drawLine(t, co, axismtx[2], 'Z', options); | ||||
| } | } | ||||
| options &= ~DRAWLIGHT; | options &= ~DRAWLIGHT; | ||||
| } | } | ||||
| } // FIXME(indent) | |||||
| } | } | ||||
| /*--------------------- START / STOP CONSTRAINTS ---------------------- */ | /*--------------------- START / STOP CONSTRAINTS ---------------------- */ | ||||
| void startConstraint(TransInfo *t) | void startConstraint(TransInfo *t) | ||||
| { | { | ||||
| t->con.mode |= CON_APPLY; | t->con.mode |= CON_APPLY; | ||||
| *t->con.text = ' '; | *t->con.text = ' '; | ||||
| ▲ Show 20 Lines • Show All 250 Lines • Show Last 20 Lines | |||||