Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_constraints.c
| Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "transform.h" | #include "transform.h" | ||||
| #include "transform_data.h" | |||||
| #include "transform_snap.h" | #include "transform_snap.h" | ||||
| /* Own include. */ | /* Own include. */ | ||||
| #include "transform_constraints.h" | #include "transform_constraints.h" | ||||
| static void drawObjectConstraint(TransInfo *t); | static void drawObjectConstraint(TransInfo *t); | ||||
| static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) | static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) | ||||
| ▲ Show 20 Lines • Show All 290 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( | static void applyAxisConstraintVec( | ||||
| TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3]) | TransInfo *t, TransDataContainer *UNUSED(tc), const int tdi, const float in[3], float out[3]) | ||||
| { | { | ||||
| copy_v3_v3(out, in); | copy_v3_v3(out, in); | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!tdi && 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 (!validSnap(t)) { | if (!validSnap(t)) { | ||||
| const int dims = getConstraintSpaceDimension(t); | const int dims = getConstraintSpaceDimension(t); | ||||
| if (dims == 2) { | if (dims == 2) { | ||||
| if (!is_zero_v3(out)) { | if (!is_zero_v3(out)) { | ||||
| if (!isPlaneProjectionViewAligned(t)) { | if (!isPlaneProjectionViewAligned(t)) { | ||||
| Show All 27 Lines | |||||
| * 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( | static void applyObjectConstraintVec( | ||||
| TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3]) | TransInfo *t, TransDataContainer *tc, const int tdi, const float in[3], float out[3]) | ||||
| { | { | ||||
| if (!td) { | if (!tdi) { | ||||
| applyAxisConstraintVec(t, tc, td, in, out); | applyAxisConstraintVec(t, tc, tdi, in, out); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Specific TransData's space. */ | /* Specific TransData's space. */ | ||||
| TransData *td = tc->data; | |||||
| copy_v3_v3(out, in); | copy_v3_v3(out, in); | ||||
| mul_m3_v3(t->spacemtx_inv, out); | mul_m3_v3(t->spacemtx_inv, out); | ||||
| mul_m3_v3(td->axismtx, out); | mul_m3_v3(td->space[tdi].axismtx, out); | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_v3(tc->mat3_unit, out); | mul_m3_v3(tc->mat3_unit, 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, | static void applyAxisConstraintSize(TransInfo *t, | ||||
| TransDataContainer *UNUSED(tc), | TransDataContainer *UNUSED(tc), | ||||
| TransData *td, | const int tdi, | ||||
| float smat[3][3]) | float smat[3][3]) | ||||
| { | { | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!tdi && 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->spacemtx_inv); | mul_m3_m3m3(tmat, smat, t->spacemtx_inv); | ||||
| mul_m3_m3m3(smat, t->spacemtx, tmat); | mul_m3_m3m3(smat, t->spacemtx, 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, | static void applyObjectConstraintSize(TransInfo *t, | ||||
| TransDataContainer *tc, | TransDataContainer *tc, | ||||
| TransData *td, | const int tdi, | ||||
| float smat[3][3]) | float smat[3][3]) | ||||
| { | { | ||||
| if (td && t->con.mode & CON_APPLY) { | if (tdi && t->con.mode & CON_APPLY) { | ||||
| TransData *td = tc->data; | |||||
| 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->space[tdi].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, tc->mat3_unit, smat); | mul_m3_m3m3(smat, tc->mat3_unit, smat); | ||||
| } | } | ||||
| mul_m3_m3m3(smat, td->axismtx, tmat); | mul_m3_m3m3(smat, td->space[tdi].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( | static void applyAxisConstraintRot( | ||||
| TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, float vec[3], float *angle) | TransInfo *t, TransDataContainer *UNUSED(tc), const int tdi, float vec[3], float *angle) | ||||
| { | { | ||||
| if (!td && t->con.mode & CON_APPLY) { | if (!tdi && 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->spacemtx[0]); | copy_v3_v3(vec, t->spacemtx[0]); | ||||
| break; | break; | ||||
| case CON_AXIS1: | case CON_AXIS1: | ||||
| Show All 24 Lines | |||||
| * | * | ||||
| * 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( | static void applyObjectConstraintRot( | ||||
| TransInfo *t, TransDataContainer *tc, TransData *td, float vec[3], float *angle) | TransInfo *t, TransDataContainer *tc, int tdi, float vec[3], float *angle) | ||||
| { | { | ||||
| if (t->con.mode & CON_APPLY) { | if (t->con.mode & CON_APPLY) { | ||||
| TransData *td = tc->data; | |||||
| 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 (tc == NULL) { | ||||
| BLI_assert(tc == NULL); | |||||
| tc = TRANS_DATA_CONTAINER_FIRST_OK(t); | tc = TRANS_DATA_CONTAINER_FIRST_OK(t); | ||||
| td = tc->data; | tdi = 0; | ||||
| } | } | ||||
| if (t->flag & T_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); | mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->space[tdi].axismtx); | ||||
| axismtx = tmp_axismtx; | axismtx = tmp_axismtx; | ||||
| } | } | ||||
| else { | else { | ||||
| axismtx = td->axismtx; | axismtx = td->space[tdi].axismtx; | ||||
| } | } | ||||
| switch (mode) { | switch (mode) { | ||||
| case CON_AXIS0: | case CON_AXIS0: | ||||
| case (CON_AXIS1 | CON_AXIS2): | case (CON_AXIS1 | CON_AXIS2): | ||||
| copy_v3_v3(vec, axismtx[0]); | copy_v3_v3(vec, axismtx[0]); | ||||
| break; | break; | ||||
| case CON_AXIS1: | case CON_AXIS1: | ||||
| Show All 25 Lines | void setConstraint(TransInfo *t, int mode, const char text[]) | ||||
| t->con.drawExtra = NULL; | t->con.drawExtra = NULL; | ||||
| t->con.applyVec = applyAxisConstraintVec; | t->con.applyVec = applyAxisConstraintVec; | ||||
| 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->space[tdi].axismtx constraints */ | ||||
| void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) | void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) | ||||
| { | { | ||||
| BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); | BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); | ||||
| t->con.mode = mode; | t->con.mode = mode; | ||||
| projection_matrix_calc(t, t->con.pmtx); | projection_matrix_calc(t, t->con.pmtx); | ||||
| startConstraint(t); | startConstraint(t); | ||||
| ▲ Show 20 Lines • Show All 190 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; | ||||
| int i; | |||||
| float tmp_axismtx[3][3]; | float tmp_axismtx[3][3]; | ||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| TransData *td = tc->data; | TransData *td = tc->data; | ||||
| for (i = 0; i < tc->data_len; i++, td++) { | for (int tdi = 0; tdi < tc->data_len; tdi++) { | ||||
| 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->prop[tdi].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_EDIT) { | if (t->flag & T_EDIT) { | ||||
| mul_v3_m4v3(co, tc->mat, td->center); | mul_v3_m4v3(co, tc->mat, td->center[tdi]); | ||||
| mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); | mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->space[tdi].axismtx); | ||||
| axismtx = tmp_axismtx; | axismtx = tmp_axismtx; | ||||
| } | } | ||||
| else if (t->flag & T_POSE) { | else if (t->flag & T_POSE) { | ||||
| mul_v3_m4v3(co, tc->mat, td->center); | mul_v3_m4v3(co, tc->mat, td->center[tdi]); | ||||
| axismtx = td->axismtx; | axismtx = td->space[tdi].axismtx; | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(co, td->center); | copy_v3_v3(co, td->center[tdi]); | ||||
| axismtx = td->axismtx; | axismtx = td->space[tdi].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); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 257 Lines • Show Last 20 Lines | |||||