diff options
Diffstat (limited to 'source/blender/editors/transform/transform_manipulator.c')
-rw-r--r-- | source/blender/editors/transform/transform_manipulator.c | 2206 |
1 files changed, 958 insertions, 1248 deletions
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 193a29928ef..1839583015c 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -59,24 +59,37 @@ #include "BKE_editmesh.h" #include "BKE_lattice.h" #include "BKE_gpencil.h" +#include "BKE_workspace.h" #include "BIF_gl.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_armature.h" #include "ED_curve.h" +#include "ED_object.h" #include "ED_particle.h" #include "ED_view3d.h" #include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_manipulator_library.h" #include "UI_resources.h" /* local module include */ #include "transform.h" +#include "MEM_guardedalloc.h" + #include "GPU_select.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#define USE_AXIS_BOUNDS /* return codes for select, and drawing flags */ @@ -88,35 +101,348 @@ #define MAN_ROT_X (1 << 3) #define MAN_ROT_Y (1 << 4) #define MAN_ROT_Z (1 << 5) -#define MAN_ROT_V (1 << 6) -#define MAN_ROT_T (1 << 7) -#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z | MAN_ROT_V | MAN_ROT_T) +#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z) #define MAN_SCALE_X (1 << 8) #define MAN_SCALE_Y (1 << 9) #define MAN_SCALE_Z (1 << 10) #define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z) -/* color codes */ - -#define MAN_RGB 0 -#define MAN_GHOST 1 -#define MAN_MOVECOL 2 - /* threshold for testing view aligned manipulator axis */ #define TW_AXIS_DOT_MIN 0.02f #define TW_AXIS_DOT_MAX 0.1f +/* axes as index */ +enum { + MAN_AXIS_TRANS_X = 0, + MAN_AXIS_TRANS_Y, + MAN_AXIS_TRANS_Z, + MAN_AXIS_TRANS_C, + + MAN_AXIS_TRANS_XY, + MAN_AXIS_TRANS_YZ, + MAN_AXIS_TRANS_ZX, +#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X +#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1) + + MAN_AXIS_ROT_X, + MAN_AXIS_ROT_Y, + MAN_AXIS_ROT_Z, + MAN_AXIS_ROT_C, + MAN_AXIS_ROT_T, /* trackball rotation */ +#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X +#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1) + + MAN_AXIS_SCALE_X, + MAN_AXIS_SCALE_Y, + MAN_AXIS_SCALE_Z, + MAN_AXIS_SCALE_C, + MAN_AXIS_SCALE_XY, + MAN_AXIS_SCALE_YZ, + MAN_AXIS_SCALE_ZX, +#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X +#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1) + + MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END, +}; + +/* axis types */ +enum { + MAN_AXES_ALL = 0, + MAN_AXES_TRANSLATE, + MAN_AXES_ROTATE, + MAN_AXES_SCALE, +}; + +typedef struct ManipulatorGroup { + bool all_hidden; + + struct wmManipulator *manipulators[MAN_AXIS_LAST]; +} ManipulatorGroup; + struct TransformBounds { float center[3]; /* Center for transform widget. */ float min[3], max[3]; /* Boundbox of selection for transform widget. */ + +#ifdef USE_AXIS_BOUNDS + /* Normalized axis */ + float axis[3][3]; + float axis_min[3], axis_max[3]; +#endif }; +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/* loop over axes */ +#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \ + axis = manipulator_get_axis_from_index(man, axis_idx); + +#define MAN_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST)); + return man->manipulators[axis_idx]; +} + +static short manipulator_get_axis_type(const int axis_idx) +{ + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { + return MAN_AXES_TRANSLATE; + } + if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { + return MAN_AXES_ROTATE; + } + if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) { + return MAN_AXES_SCALE; + } + BLI_assert(0); + return -1; +} + +static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane) +{ + switch (axis_idx) { + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + return 0; + + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + return 1; + + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + return 2; + } + return 3; +} + +static bool manipulator_is_axis_visible( + const View3D *v3d, const RegionView3D *rv3d, + const float idot[3], const int axis_type, const int axis_idx) +{ + bool is_plane = false; + const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* don't draw axis perpendicular to the view */ + if (aidx_norm < 3) { + float idot_axis = idot[aidx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + if (idot_axis < TW_AXIS_DOT_MIN) { + return false; + } + } + + if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) || + (axis_type == MAN_AXES_ROTATE && !(v3d->twtype & V3D_MANIP_ROTATE)) || + (axis_type == MAN_AXES_SCALE && !(v3d->twtype & V3D_MANIP_SCALE))) + { + return false; + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + return (rv3d->twdrawflag & MAN_TRANS_X); + case MAN_AXIS_TRANS_Y: + return (rv3d->twdrawflag & MAN_TRANS_Y); + case MAN_AXIS_TRANS_Z: + return (rv3d->twdrawflag & MAN_TRANS_Z); + case MAN_AXIS_TRANS_C: + return (rv3d->twdrawflag & MAN_TRANS_C); + case MAN_AXIS_ROT_X: + return (rv3d->twdrawflag & MAN_ROT_X); + case MAN_AXIS_ROT_Y: + return (rv3d->twdrawflag & MAN_ROT_Y); + case MAN_AXIS_ROT_Z: + return (rv3d->twdrawflag & MAN_ROT_Z); + case MAN_AXIS_ROT_C: + case MAN_AXIS_ROT_T: + return (rv3d->twdrawflag & MAN_ROT_C); + case MAN_AXIS_SCALE_X: + return (rv3d->twdrawflag & MAN_SCALE_X); + case MAN_AXIS_SCALE_Y: + return (rv3d->twdrawflag & MAN_SCALE_Y); + case MAN_AXIS_SCALE_Z: + return (rv3d->twdrawflag & MAN_SCALE_Z); + case MAN_AXIS_SCALE_C: + return (rv3d->twdrawflag & MAN_SCALE_C && (v3d->twtype & V3D_MANIP_TRANSLATE) == 0); + case MAN_AXIS_TRANS_XY: + return (rv3d->twdrawflag & MAN_TRANS_X && + rv3d->twdrawflag & MAN_TRANS_Y && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_YZ: + return (rv3d->twdrawflag & MAN_TRANS_Y && + rv3d->twdrawflag & MAN_TRANS_Z && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_ZX: + return (rv3d->twdrawflag & MAN_TRANS_Z && + rv3d->twdrawflag & MAN_TRANS_X && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_XY: + return (rv3d->twdrawflag & MAN_SCALE_X && + rv3d->twdrawflag & MAN_SCALE_Y && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_YZ: + return (rv3d->twdrawflag & MAN_SCALE_Y && + rv3d->twdrawflag & MAN_SCALE_Z && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_ZX: + return (rv3d->twdrawflag & MAN_SCALE_Z && + rv3d->twdrawflag & MAN_SCALE_X && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + } + return false; +} + +static void manipulator_get_axis_color( + const int axis_idx, const float idot[3], + float r_col[4], float r_col_hi[4]) +{ + /* alpha values for normal/highlighted states */ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + float alpha_fac; + + bool is_plane = false; + const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */ + if (axis_idx_norm < 3) { + float idot_axis = idot[axis_idx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ? + 1.0f : (idot_axis < TW_AXIS_DOT_MIN) ? + 0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN)); + } + else { + /* trackball rotation axis is a special case, we only draw a slight overlay */ + alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f; + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + UI_GetThemeColor4fv(TH_AXIS_X, r_col); + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + UI_GetThemeColor4fv(TH_AXIS_Y, r_col); + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + UI_GetThemeColor4fv(TH_AXIS_Z, r_col); + break; + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + copy_v4_fl(r_col, 1.0f); + break; + } + + copy_v4_v4(r_col_hi, r_col); + + r_col[3] = alpha * alpha_fac; + r_col_hi[3] = alpha_hi * alpha_fac; +} + +static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3]) +{ + zero_v3_int(r_axis); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + r_axis[0] = 1; + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + r_axis[0] = r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + r_axis[1] = r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + r_axis[2] = r_axis[0] = 1; + break; + default: + break; + } +} + + +/* **************** Preparation Stuff **************** */ + /* transform widget center calc helper for below */ static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) { minmax_v3v3_v3(tbounds->min, tbounds->max, co); add_v3_v3(tbounds->center, co); + +#ifdef USE_AXIS_BOUNDS + for (int i = 0; i < 3; i++) { + const float d = dot_v3v3(tbounds->axis[i], co); + tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]); + tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]); + } +#endif } static void protectflag_to_drawflags(short protectflag, short *drawflags) @@ -194,9 +520,9 @@ static bool test_rotmode_euler(short rotmode) return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; } -bool gimbal_axis(Object *ob, float gmat[3][3]) +bool gimbal_axis(Object *ob, float gmat[3][3], const eObjectMode object_mode) { - if (ob->mode & OB_MODE_POSE) { + if (object_mode & OB_MODE_POSE) { bPoseChannel *pchan = BKE_pose_channel_active(ob); if (pchan) { @@ -261,16 +587,20 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) /* centroid, boundbox, of selection */ /* returns total items selected */ -static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds) +static int calc_manipulator_stats( + const bContext *C, bool use_only_center, + struct TransformBounds *tbounds) { + const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; Base *base; - Object *ob = OBACT; + Object *ob = OBACT(view_layer); bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); int a, totsel = 0; @@ -278,12 +608,104 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* transform widget matrix */ unit_m4(rv3d->twmat); +#ifdef USE_AXIS_BOUNDS + unit_m3(rv3d->tw_axis_matrix); + zero_v3(rv3d->tw_axis_min); + zero_v3(rv3d->tw_axis_max); +#endif + rv3d->twdrawflag = 0xFFFF; + /* global, local or normal orientation? + * if we could check 'totsel' now, this should be skipped with no selection. */ + if (ob && !is_gp_edit) { + + switch (v3d->twmode) { + + case V3D_MANIP_GLOBAL: + { + break; /* nothing to do */ + } + case V3D_MANIP_GIMBAL: + { + float mat[3][3]; + if (gimbal_axis(ob, mat, workspace->object_mode)) { + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_NORMAL: + { + if (obedit || workspace->object_mode & OB_MODE_POSE) { + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_LOCAL: + { + if (workspace->object_mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single bone + * and users who select many bones will understand whats going on and what local means + * when they start transforming */ + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + copy_m4_m4(rv3d->twmat, ob->obmat); + normalize_m4(rv3d->twmat); + break; + } + case V3D_MANIP_VIEW: + { + float mat[3][3]; + copy_m3_m4(mat, rv3d->viewinv); + normalize_m3(mat); + copy_m4_m3(rv3d->twmat, mat); + break; + } + case V3D_MANIP_CUSTOM: + { + TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find( + CTX_wm_workspace(C), v3d->custom_orientation_index); + float mat[3][3]; + + if (applyTransformOrientation(custom_orientation, mat, NULL)) { + copy_m4_m3(rv3d->twmat, mat); + } + break; + } + } + } + /* transform widget centroid/center */ INIT_MINMAX(tbounds->min, tbounds->max); zero_v3(tbounds->center); +#ifdef USE_AXIS_BOUNDS + copy_m3_m4(tbounds->axis, rv3d->twmat); + if (ob && workspace->object_mode & OB_MODE_EDIT) { + float diff_mat[3][3]; + copy_m3_m4(diff_mat, ob->obmat); + normalize_m3(diff_mat); + invert_m3(diff_mat); + mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); + normalize_m3(tbounds->axis); + } + + for (int i = 0; i < 3; i++) { + tbounds->axis_min[i] = +FLT_MAX; + tbounds->axis_max[i] = -FLT_MAX; + } +#endif + if (is_gp_edit) { float diff_mat[4][4]; float fpt[3]; @@ -330,13 +752,11 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ } } else if (obedit) { ob = obedit; - if ((ob->lay & v3d->lay) == 0) return 0; - if (obedit->type == OB_MESH) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMEditSelection ese; @@ -442,15 +862,11 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo } else { if (bezt->f1 & SELECT) { - calc_tw_center( - tbounds, - bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center( - tbounds, - bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -512,19 +928,17 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! mul_m4_v3(obedit->obmat, tbounds->center); mul_m4_v3(obedit->obmat, tbounds->min); mul_m4_v3(obedit->obmat, tbounds->max); } } - else if (ob && (ob->mode & OB_MODE_POSE)) { + else if (ob && (workspace->object_mode & OB_MODE_POSE)) { bPoseChannel *pchan; int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed bool ok = false; - if ((ob->lay & v3d->lay) == 0) return 0; - if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; @@ -552,17 +966,17 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo } if (ok) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! mul_m4_v3(ob->obmat, tbounds->center); mul_m4_v3(ob->obmat, tbounds->min); mul_m4_v3(ob->obmat, tbounds->max); } } - else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { + else if (ob && (workspace->object_mode & OB_MODE_ALL_PAINT)) { /* pass */ } - else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - PTCacheEdit *edit = PE_get_current(scene, ob); + else if (ob && workspace->object_mode & OB_MODE_PARTICLE_EDIT) { + PTCacheEdit *edit = PE_get_current(scene, view_layer, ob); PTCacheEditPoint *point; PTCacheEditKey *ek; int k; @@ -582,20 +996,30 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } else { /* we need the one selected object, if its not active */ - ob = OBACT; - if (ob && !(ob->flag & SELECT)) ob = NULL; + base = BASACT(view_layer); + ob = OBACT(view_layer); + if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { + for (base = view_layer->object_bases.first; base; base = base->next) { + if (TESTBASELIB(base)) { if (ob == NULL) ob = base->object; - calc_tw_center(tbounds, base->object->obmat[3]); + if (use_only_center || base->object->bb == NULL) { + calc_tw_center(tbounds, base->object->obmat[3]); + } + else { + for (uint j = 0; j < 8; j++) { + float co[3]; + mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]); + calc_tw_center(tbounds, co); + } + } protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -603,1379 +1027,665 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } - /* global, local or normal orientation? */ - if (ob && totsel && !is_gp_edit) { - - switch (v3d->twmode) { - - case V3D_MANIP_GLOBAL: - { - break; /* nothing to do */ - } - case V3D_MANIP_GIMBAL: - { - float mat[3][3]; - if (gimbal_axis(ob, mat)) { - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_NORMAL: - { - if (obedit || ob->mode & OB_MODE_POSE) { - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_LOCAL: - { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand whats going on and what local means - * when they start transforming */ - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - copy_m4_m4(rv3d->twmat, ob->obmat); - normalize_m4(rv3d->twmat); - break; - } - case V3D_MANIP_VIEW: - { - float mat[3][3]; - copy_m3_m4(mat, rv3d->viewinv); - normalize_m3(mat); - copy_m4_m3(rv3d->twmat, mat); - break; - } - default: /* V3D_MANIP_CUSTOM */ - { - float mat[3][3]; - if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) { - copy_m4_m3(rv3d->twmat, mat); - } - break; - } - } - + if (totsel == 0) { + unit_m4(rv3d->twmat); + } + else { +#ifdef USE_AXIS_BOUNDS + copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min); + copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max); + copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis); +#endif } return totsel; } -/* don't draw axis perpendicular to the view */ -static void test_manipulator_axis(const bContext *C) +static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3]) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); float view_vec[3], axis_vec[3]; - float idot; - int i; - - const int twdrawflag_axis[3] = { - (MAN_TRANS_X | MAN_SCALE_X), - (MAN_TRANS_Y | MAN_SCALE_Y), - (MAN_TRANS_Z | MAN_SCALE_Z)}; - ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec); - - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { normalize_v3_v3(axis_vec, rv3d->twmat[i]); - rv3d->tw_idot[i] = idot = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); - if (idot < TW_AXIS_DOT_MIN) { - rv3d->twdrawflag &= ~twdrawflag_axis[i]; - } + r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); } } - -/* ******************** DRAWING STUFFIES *********** */ - -static float screen_aligned(RegionView3D *rv3d, float mat[4][4]) -{ - glTranslate3fv(mat[3]); - - /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); - - return len_v3(mat[0]); /* draw scale */ -} - - -/** - * \param radring: Radius of doughnut rings. - * \param radhole: Radius hole. - * \param start: Starting segment (based on \a nrings). - * \param end: End segment. - * \param nsides: Number of points in ring. - * \param nrings: Number of rings. - */ -static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings) +static void manipulator_prepare_mat( + const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds) { - float theta, phi, theta1; - float cos_theta, sin_theta; - float cos_theta1, sin_theta1; - float ring_delta, side_delta; - int i, j, do_caps = true; - - if (start == 0 && end == nrings) do_caps = false; - - ring_delta = 2.0f * (float)M_PI / (float)nrings; - side_delta = 2.0f * (float)M_PI / (float)nsides; - - theta = (float)M_PI + 0.5f * ring_delta; - cos_theta = cosf(theta); - sin_theta = sinf(theta); - - for (i = nrings - 1; i >= 0; i--) { - theta1 = theta + ring_delta; - cos_theta1 = cosf(theta1); - sin_theta1 = sinf(theta1); - - if (do_caps && i == start) { // cap - glBegin(GL_POLYGON); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi += side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); - } - glEnd(); - } - if (i >= start && i <= end) { - glBegin(GL_QUAD_STRIP); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi += side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + switch (v3d->around) { + case V3D_AROUND_CENTER_BOUNDS: + case V3D_AROUND_ACTIVE: + { + const WorkSpace *workspace = CTX_wm_workspace(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = OBACT(view_layer); + + if (((v3d->around == V3D_AROUND_ACTIVE) && ((workspace->object_mode & OB_MODE_EDIT) == 0)) && + ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && + (!(workspace->object_mode & OB_MODE_POSE))) + { + copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); } - glEnd(); - } - - if (do_caps && i == end) { // cap - glBegin(GL_POLYGON); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi -= side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + else { + mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); } - glEnd(); + break; } - - - theta = theta1; - cos_theta = cos_theta1; - sin_theta = sin_theta1; - } -} - -static char axisBlendAngle(float idot) -{ - if (idot > TW_AXIS_DOT_MAX) { - return 255; - } - else if (idot < TW_AXIS_DOT_MIN) { - return 0; - } - else { - return (char)(255.0f * (idot - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN)); + case V3D_AROUND_LOCAL_ORIGINS: + case V3D_AROUND_CENTER_MEAN: + copy_v3_v3(rv3d->twmat[3], tbounds->center); + break; + case V3D_AROUND_CURSOR: + copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); + break; } } -/* three colors can be set: - * gray for ghosting - * moving: in transform theme color - * else the red/green/blue +/** + * Sets up \a r_start and \a r_len to define arrow line range. + * Needed to adjust line drawing for combined manipulator axis types. */ -static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha) +static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len) { - unsigned char col[4] = {0}; - col[3] = alpha; + const float ofs = 0.2f; - if (colcode == MAN_GHOST) { - col[3] = 70; - } - else if (colcode == MAN_MOVECOL) { - UI_GetThemeColor3ubv(TH_TRANSFORM, col); - } - else { - switch (axis) { - case 'C': - UI_GetThemeColor3ubv(TH_TRANSFORM, col); - if (v3d->twmode == V3D_MANIP_LOCAL) { - col[0] = col[0] > 200 ? 255 : col[0] + 55; - col[1] = col[1] > 200 ? 255 : col[1] + 55; - col[2] = col[2] > 200 ? 255 : col[2] + 55; - } - else if (v3d->twmode == V3D_MANIP_NORMAL) { - col[0] = col[0] < 55 ? 0 : col[0] - 55; - col[1] = col[1] < 55 ? 0 : col[1] - 55; - col[2] = col[2] < 55 ? 0 : col[2] - 55; - } - break; - case 'X': - UI_GetThemeColor3ubv(TH_AXIS_X, col); - break; - case 'Y': - UI_GetThemeColor3ubv(TH_AXIS_Y, col); - break; - case 'Z': - UI_GetThemeColor3ubv(TH_AXIS_Z, col); - break; - default: - BLI_assert(0); - break; - } - } - - glColor4ubv(col); -} - -static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3]) -{ - float axis_values[3]; - float vec[3]; + *r_start = 0.2f; + *r_len = 1.0f; - ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec); - - axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec); - axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec); - axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec); - - axis_sort_v3(axis_values, r_axis_order); -} - -/* viewmatrix should have been set OK, also no shademode! */ -static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode, - int flagx, int flagy, int flagz, int axis, - const bool is_picksel) -{ - switch (axis) { - case 0: - /* axes */ - if (flagx) { - if (is_picksel) { - if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X); - else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X); - } - else { - manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - } - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (v3d->twtype & V3D_MANIP_SCALE) { + *r_start = *r_len - ofs + 0.075f; } - break; - case 1: - if (flagy) { - if (is_picksel) { - if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y); - else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y); - } - else { - manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); + if (v3d->twtype & V3D_MANIP_ROTATE) { + *r_len += ofs; } break; - case 2: - if (flagz) { - if (is_picksel) { - if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z); - else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z); - } - else { - manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); + case MAN_AXES_SCALE: + if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) { + *r_len -= ofs + 0.025f; } break; } -} -static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, - int flagx, int flagy, int flagz, - const int axis_order[3], const bool is_picksel) -{ - int i; - for (i = 0; i < 3; i++) { - draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel); - } -} -static void preOrthoFront(const bool ortho, float twmat[4][4], int axis) -{ - if (ortho == false) { - float omat[4][4]; - copy_m4_m4(omat, twmat); - orthogonalize_m4(omat, axis); - glPushMatrix(); - glMultMatrixf(omat); - glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW); - } + *r_len -= *r_start; } -static void postOrtho(const bool ortho) +static void manipulator_xform_message_subscribe( + wmManipulatorGroup *mgroup, struct wmMsgBus *mbus, + bScreen *screen, ScrArea *sa, ARegion *ar, const void *type_fn) { - if (ortho == false) { - glPopMatrix(); - } -} + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; -BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags) -{ - return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)); -} + PointerRNA space_ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &space_ptr); -static void draw_manipulator_rotate( - View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, - const bool is_moving, const bool is_picksel) -{ - double plane[4]; - float matt[4][4]; - float size, unitmat[4][4]; - float cywid = 0.33f * 0.01f * (float)U.tw_handlesize; - float cusize = cywid * 0.65f; - int arcs = (G.debug_value != 2); - const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB; - bool ortho; - - /* skip drawing if all axes are locked */ - if (manipulator_rotate_is_visible(drawflags) == false) return; - - /* Init stuff */ - glDisable(GL_DEPTH_TEST); - unit_m4(unitmat); - - /* prepare for screen aligned draw */ - size = len_v3(rv3d->twmat[0]); - glPushMatrix(); - glTranslate3fv(rv3d->twmat[3]); - - if (arcs) { - /* clipplane makes nice handles, calc here because of multmatrix but with translate! */ - copy_v3db_v3fl(plane, rv3d->viewinv[2]); - plane[3] = -0.02f * size; // clip just a bit more - glClipPlane(GL_CLIP_PLANE0, plane); - } - /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); - - /* Screen aligned help circle */ - if (arcs) { - if (is_picksel == false) { - UI_ThemeColorShade(TH_BACK, -30); - drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat); + { + extern PropertyRNA rna_SpaceView3D_transform_orientation; + const PropertyRNA *props[] = { + &rna_SpaceView3D_transform_orientation, + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); } } - /* Screen aligned trackball rot circle */ - if (drawflags & MAN_ROT_T) { - if (is_picksel) GPU_select_load_id(MAN_ROT_T); - else UI_ThemeColor(TH_TRANSFORM); - - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - } - - /* Screen aligned view rot circle */ - if (drawflags & MAN_ROT_V) { - if (is_picksel) GPU_select_load_id(MAN_ROT_V); - else UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); - - if (is_moving) { - float vec[3]; - vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); - vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); - vec[2] = 0.0f; - normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3fv(vec); - glEnd(); + if (type_fn == TRANSFORM_WGT_manipulator) { + extern PropertyRNA rna_SpaceView3D_pivot_point; + const PropertyRNA *props[] = { + &rna_SpaceView3D_pivot_point + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); } } - glPopMatrix(); - - - ortho = is_orthogonal_m4(rv3d->twmat); - - /* apply the transform delta */ - if (is_moving) { - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - if (ortho) { - glMultMatrixf(matt); - glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); - } + else if (type_fn == VIEW3D_WGT_xform_cage) { + /* pass */ } else { - if (ortho) { - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - glMultMatrixf(rv3d->twmat); - } + BLI_assert(0); } - /* axes */ - if (arcs == 0) { - if (!is_picksel) { - if ((combo & V3D_MANIP_SCALE) == 0) { - /* axis */ - if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) { - preOrthoFront(ortho, rv3d->twmat, 2); - manipulator_setcolor(v3d, 'X', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); - postOrtho(ortho); - } - if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) { - preOrthoFront(ortho, rv3d->twmat, 0); - manipulator_setcolor(v3d, 'Y', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - postOrtho(ortho); - } - if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) { - preOrthoFront(ortho, rv3d->twmat, 1); - manipulator_setcolor(v3d, 'Z', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); - postOrtho(ortho); - } - } - } - } + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); +} - if (arcs == 0 && is_moving) { +/** \} */ - /* Z circle */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, matt, 2); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - postOrtho(ortho); - } - /* X circle */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, matt, 0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(-90.0, 0.0, 1.0, 0.0); - postOrtho(ortho); - } - /* Y circle */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, matt, 1); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(90.0, 1.0, 0.0, 0.0); - postOrtho(ortho); - } - } - // donut arcs - if (arcs) { - glEnable(GL_CLIP_PLANE0); - - /* Z circle */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, rv3d->twmat, 2); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - postOrtho(ortho); - } - /* X circle */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, rv3d->twmat, 0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(-90.0, 0.0, 1.0, 0.0); - postOrtho(ortho); - } - /* Y circle */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, rv3d->twmat, 1); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(90.0, 1.0, 0.0, 0.0); - postOrtho(ortho); - } - glDisable(GL_CLIP_PLANE0); - } +/* -------------------------------------------------------------------- */ +/** \name Transform Manipulator + * \{ */ - if (arcs == 0) { +static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man; - /* Z handle on X axis */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, rv3d->twmat, 2); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); + man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data"); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); + const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true); - glPopMatrix(); - postOrtho(ortho); - } +#define MANIPULATOR_NEW_ARROW(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ +} ((void)0) +#define MANIPULATOR_NEW_DIAL(v, draw_options) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ +} ((void)0) +#define MANIPULATOR_NEW_PRIM(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ +} ((void)0) - /* Y handle on X axis */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, rv3d->twmat, 1); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); + /* add/init widgets - order matters! */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); - glRotatef(90.0, 1.0, 0.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - glPopMatrix(); - postOrtho(ortho); - } + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX); - /* X handle on Z axis */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, rv3d->twmat, 0); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - glPopMatrix(); - postOrtho(ortho); - } + /* init screen aligned widget last here, looks better, behaves better */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - } + MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - /* restore */ - glLoadMatrixf(rv3d->viewmat); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL); -} + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); -static void drawsolidcube(float size) -{ - const float cube[8][3] = { - {-1.0, -1.0, -1.0}, - {-1.0, -1.0, 1.0}, - {-1.0, 1.0, 1.0}, - {-1.0, 1.0, -1.0}, - { 1.0, -1.0, -1.0}, - { 1.0, -1.0, 1.0}, - { 1.0, 1.0, 1.0}, - { 1.0, 1.0, -1.0}, - }; - float n[3] = {0.0f}; - - glPushMatrix(); - glScalef(size, size, size); - - glBegin(GL_QUADS); - n[0] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[0] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); - n[2] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); - glEnd(); - - glPopMatrix(); + return man; } - -static void draw_manipulator_scale( - View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, const int colcode, - const bool is_moving, const bool is_picksel) +/** + * Custom handler for manipulator widgets + */ +static int manipulator_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) { - float cywid = 0.25f * 0.01f * (float)U.tw_handlesize; - float cusize = cywid * 0.75f, dz; - int axis_order[3] = {2, 0, 1}; - int i; - - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_SCALE_C) == 0) return; - - manipulator_axis_order(rv3d, axis_order); - - glDisable(GL_DEPTH_TEST); - - /* not in combo mode */ - if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) { - float size, unitmat[4][4]; - int shift = 0; // XXX - - /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); - else manipulator_setcolor(v3d, 'C', colcode, 255); + const ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); - dz = 1.0; - } - else { - dz = 1.0f - 4.0f * cusize; + if (calc_manipulator_stats(C, true, &tbounds)) { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]); } - if (is_moving) { - float matt[4][4]; + ED_region_tag_redraw(ar); - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - glMultMatrixf(matt); - glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); - } - else { - glMultMatrixf(rv3d->twmat); - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - } + return OPERATOR_RUNNING_MODAL; +} - /* axis */ +static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = manipulatorgroup_init(mgroup); + struct { + wmOperatorType *translate, *rotate, *trackball, *resize; + } ot_store = {NULL}; - /* in combo mode, this is always drawn as first type */ - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z, - axis_order, is_picksel); + mgroup->customdata = man; + /* *** set properties for axes *** */ - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* X cube */ - if (drawflags & MAN_SCALE_X) { - glTranslatef(dz, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_SCALE_X); - else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - drawsolidcube(cusize); - glTranslatef(-dz, 0.0, 0.0); - } + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + int constraint_axis[3] = {1, 0, 0}; + PointerRNA *ptr; + + manipulator_get_axis_constraint(axis_idx, constraint_axis); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator_modal); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); break; - case 1: /* Y cube */ - if (drawflags & MAN_SCALE_Y) { - glTranslatef(0.0, dz, 0.0); - if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); - else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - drawsolidcube(cusize); - glTranslatef(0.0, -dz, 0.0); - } + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + /* increased line width for better display */ + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); break; - case 2: /* Z cube */ - if (drawflags & MAN_SCALE_Z) { - glTranslatef(0.0, 0.0, dz); - if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); - else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - drawsolidcube(cusize); - glTranslatef(0.0, 0.0, -dz); - } + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float ofs_ax = 11.0f; + const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; + WM_manipulator_set_scale(axis, 0.07f); + WM_manipulator_set_matrix_offset_location(axis, ofs); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; - } - } - -#if 0 // XXX - /* if shiftkey, center point as last, for selectbuffer order */ - if (is_picksel) { - int shift = 0; // XXX - - if (shift) { - glTranslatef(0.0, -dz, 0.0); - GPU_select_load_id(MAN_SCALE_C); - /* TODO: set glPointSize before drawing center point */ - glBegin(GL_POINTS); - glVertex3f(0.0, 0.0, 0.0); - glEnd(); - } - } -#endif - - /* restore */ - glLoadMatrixf(rv3d->viewmat); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glFrontFace(GL_CCW); -} - - -static void draw_cone(GLUquadricObj *qobj, float len, float width) -{ - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, 0.0, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, 0.5f * len); -} - -static void draw_cylinder(GLUquadricObj *qobj, float len, float width) -{ - - width *= 0.8f; // just for beauty - - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, width, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, len); - gluDisk(qobj, 0.0, width, 8, 1); - glTranslatef(0.0, 0.0, -0.5f * len); -} - - -static void draw_manipulator_translate( - View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode, - const bool UNUSED(is_moving), const bool is_picksel) -{ - GLUquadricObj *qobj; - float cylen = 0.01f * (float)U.tw_handlesize; - float cywid = 0.25f * cylen, dz, size; - float unitmat[4][4]; - int shift = 0; // XXX - int axis_order[3] = {0, 1, 2}; - int i; - - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_TRANS_C) == 0) return; - - manipulator_axis_order(rv3d, axis_order); - - // XXX if (moving) glTranslate3fv(t->vec); - glDisable(GL_DEPTH_TEST); - - /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); - else manipulator_setcolor(v3d, 'C', colcode, 255); - - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); - - /* and now apply matrix, we move to local matrix drawing */ - glMultMatrixf(rv3d->twmat); - - /* axis */ - GPU_select_load_id(-1); - - // translate drawn as last, only axis when no combo with scale, or for ghosting - if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z, - axis_order, is_picksel); - } - - - /* offset in combo mode, for rotate a bit more */ - if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen; - else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen; - else dz = 1.0f; - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* Z Cone */ - if (drawflags & MAN_TRANS_Z) { - glTranslatef(0.0, 0.0, dz); - if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); - else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - draw_cone(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -dz); + } + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + if (axis_idx == MAN_AXIS_ROT_T) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true); } - break; - case 1: /* X Cone */ - if (drawflags & MAN_TRANS_X) { - glTranslatef(dz, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_TRANS_X); - else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - glRotatef(90.0, 0.0, 1.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-dz, 0.0, 0.0); + else if (axis_idx == MAN_AXIS_ROT_C) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); } - break; - case 2: /* Y Cone */ - if (drawflags & MAN_TRANS_Y) { - glTranslatef(0.0, dz, 0.0); - if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); - else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - glRotatef(-90.0, 1.0, 0.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -dz, 0.0); + else { + WM_manipulator_set_scale(axis, 0.2f); } break; } - } - - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - -} - -static void draw_manipulator_rotate_cyl( - View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode, - const bool is_moving, const bool is_picksel) -{ - GLUquadricObj *qobj; - float size; - float cylen = 0.01f * (float)U.tw_handlesize; - float cywid = 0.25f * cylen; - int axis_order[3] = {2, 0, 1}; - int i; - - /* skip drawing if all axes are locked */ - if (manipulator_rotate_is_visible(drawflags) == false) return; - - manipulator_axis_order(rv3d, axis_order); - - /* prepare for screen aligned draw */ - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - - glDisable(GL_DEPTH_TEST); - - qobj = gluNewQuadric(); - - /* Screen aligned view rot circle */ - if (drawflags & MAN_ROT_V) { - float unitmat[4][4]; - - unit_m4(unitmat); - - if (is_picksel) GPU_select_load_id(MAN_ROT_V); - UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); - - if (is_moving) { - float vec[3]; - vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); - vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); - vec[2] = 0.0f; - normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, 0.0); - glVertex3fv(vec); - glEnd(); - } - } - glPopMatrix(); - - /* apply the transform delta */ - if (is_moving) { - float matt[4][4]; - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX if (t->flag & T_USES_MANIPULATOR) { - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - // XXX } - glMultMatrixf(matt); - } - else { - glMultMatrixf(rv3d->twmat); - } - - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - - /* axis */ - if (is_picksel == false) { - - // only draw axis when combo didn't draw scale axes - if ((combo & V3D_MANIP_SCALE) == 0) { - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z, - axis_order, is_picksel); - } - /* only has to be set when not in picking */ - gluQuadricDrawStyle(qobj, GLU_FILL); - } - - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* X cylinder */ - if (drawflags & MAN_ROT_X) { - glTranslatef(1.0, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - glRotatef(90.0, 0.0, 1.0, 0.0); - manipulator_setcolor(v3d, 'X', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-1.0, 0.0, 0.0); + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (ot_store.translate == NULL) { + ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true); } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL); break; - case 1: /* Y cylinder */ - if (drawflags & MAN_ROT_Y) { - glTranslatef(0.0, 1.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - glRotatef(-90.0, 1.0, 0.0, 0.0); - manipulator_setcolor(v3d, 'Y', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -1.0, 0.0); + case MAN_AXES_ROTATE: + { + wmOperatorType *ot_rotate; + if (axis_idx == MAN_AXIS_ROT_T) { + if (ot_store.trackball == NULL) { + ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true); + } + ot_rotate = ot_store.trackball; } + else { + if (ot_store.rotate == NULL) { + ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + } + ot_rotate = ot_store.rotate; + } + ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL); break; - case 2: /* Z cylinder */ - if (drawflags & MAN_ROT_Z) { - glTranslatef(0.0, 0.0, 1.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - manipulator_setcolor(v3d, 'Z', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -1.0); + } + case MAN_AXES_SCALE: + { + if (ot_store.resize == NULL) { + ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true); } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL); break; + } } - } - - /* restore */ - - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + { + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) { + RNA_property_boolean_set_array(ptr, prop, constraint_axis); + } + } + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN_ITER_AXES_END; } - -/* ********************************************* */ - -/* main call, does calc centers & orientation too */ -static int drawflags = 0xFFFF; // only for the calls below, belongs in scene...? - -void BIF_draw_manipulator(const bContext *C) +static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup) { + ManipulatorGroup *man = mgroup->customdata; ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - int totsel; + struct TransformBounds tbounds; - const bool is_picksel = false; + /* skip, we don't draw anything anyway */ + if ((man->all_hidden = (calc_manipulator_stats(C, true, &tbounds) == 0))) + return; - if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return; + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); - if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return; + /* *** set properties for axes *** */ + MAN_ITER_AXES_BEGIN(axis, axis_idx) { - struct TransformBounds tbounds; - v3d->twflag &= ~V3D_DRAW_MANIPULATOR; - - totsel = calc_manipulator_stats(C, &tbounds); - if (totsel == 0) return; - - v3d->twflag |= V3D_DRAW_MANIPULATOR; - - /* now we can define center */ - switch (v3d->around) { - case V3D_AROUND_CENTER_BOUNDS: - case V3D_AROUND_ACTIVE: + const short axis_type = manipulator_get_axis_type(axis_idx); + const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL); + + WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: { - bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT; + float start_co[3] = {0.0f, 0.0f, 0.0f}; + float len; - if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && - ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && - (ob && !(ob->mode & OB_MODE_POSE))) - { - copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); - } - else { - mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max); - } + manipulator_line_range(v3d, axis_type, &start_co[2], &len); + + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); + RNA_float_set(axis->ptr, "length", len); + WM_manipulator_set_matrix_offset_location(axis, start_co); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; } - case V3D_AROUND_LOCAL_ORIGINS: - case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], tbounds.center); + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); break; - case V3D_AROUND_CURSOR: - copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; + const float *z_axis = rv3d->twmat[aidx_norm]; + WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); break; + } } - - mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size); } + MAN_ITER_AXES_END; +} + +static void WIDGETGROUP_manipulator_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, TRANSFORM_WGT_manipulator); +} + +static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = mgroup->customdata; + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + float idot[3]; /* when looking through a selected camera, the manipulator can be at the * exact same position as the view, skip so we don't break selection */ - if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) + if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) { + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + } + MAN_ITER_AXES_END; return; + } + manipulator_get_idot(rv3d, idot); - test_manipulator_axis(C); - drawflags = rv3d->twdrawflag; /* set in calc_manipulator_stats */ - - if (v3d->twflag & V3D_DRAW_MANIPULATOR) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glLineWidth(1.0f); + /* *** set properties for axes *** */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) { - if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) - draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_MOVECOL, true, is_picksel); - else - draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); - } - else { - draw_manipulator_rotate(v3d, rv3d, drawflags, v3d->twtype, false, is_picksel); - } - } - if (v3d->twtype & V3D_MANIP_SCALE) { - draw_manipulator_scale(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + /* XXX maybe unset _HIDDEN flag on redraw? */ + if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false); } - if (v3d->twtype & V3D_MANIP_TRANSLATE) { - draw_manipulator_translate(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); + else { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + continue; } - glDisable(GL_BLEND); + float color[4], color_hi[4]; + manipulator_get_axis_color(axis_idx, idot, color, color_hi); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); + + switch (axis_idx) { + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); + break; + } } + MAN_ITER_AXES_END; } -static int manipulator_selectbuf(Scene *scene, ScrArea *sa, ARegion *ar, const int mval[2], float hotspot) +static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *UNUSED(wgt)) { - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - rcti rect; - GLuint buffer[64]; // max 4 items per select, so large enuf - short hits; - const bool is_picksel = true; - const bool do_passes = GPU_select_query_check_active(); + /* it's a given we only use this in 3D view */ + const ScrArea *sa = CTX_wm_area(C); + const View3D *v3d = sa->spacedata.first; - /* when looking through a selected camera, the manipulator can be at the - * exact same position as the view, skip so we don't break selection */ - if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) - return 0; + if (((v3d->twflag & V3D_MANIPULATOR_DRAW) != 0) && + ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) != 0)) + { + /* Don't show when tools have a manipulator. */ + WorkSpace *workspace = CTX_wm_workspace(C); + if (workspace->tool.manipulator_group[0] == '\0') { + return true; + } + } + return false; +} - rect.xmin = mval[0] - hotspot; - rect.xmax = mval[0] + hotspot; - rect.ymin = mval[1] - hotspot; - rect.ymax = mval[1] + hotspot; +void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Manipulator"; + wgt->idname = "TRANSFORM_WGT_manipulator"; - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, &rect); + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D); - if (do_passes) - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); - else - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_ALL, 0); + wgt->poll = WIDGETGROUP_manipulator_poll; + wgt->setup = WIDGETGROUP_manipulator_setup; + wgt->refresh = WIDGETGROUP_manipulator_refresh; + wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe; + wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; +} - /* do the drawing */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); - } - if (v3d->twtype & V3D_MANIP_SCALE) - draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - if (v3d->twtype & V3D_MANIP_TRANSLATE) - draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); +/** \} */ - hits = GPU_select_end(); - if (do_passes && (hits > 0)) { - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); +/* -------------------------------------------------------------------- */ +/** \name Scale Cage Manipulator + * \{ */ - /* do the drawing */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); - } - if (v3d->twtype & V3D_MANIP_SCALE) - draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - if (v3d->twtype & V3D_MANIP_TRANSLATE) - draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); +struct XFormCageWidgetGroup { + wmManipulator *manipulator; +}; - GPU_select_end(); +static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + WorkSpace *workspace = CTX_wm_workspace(C); + if (!STREQ(wgt->idname, workspace->tool.manipulator_group)) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; } + return true; +} - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL); +static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); + xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + wmManipulator *mpr = xmgroup->manipulator; - if (hits == 1) return buffer[3]; - else if (hits > 1) { - GLuint val, dep, mindep = 0, mindeprot = 0, minval = 0, minvalrot = 0; - int a; + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); - /* we compare the hits in buffer, but value centers highest */ - /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */ + mpr->color[0] = 1; + mpr->color_hi[0] =1; - for (a = 0; a < hits; a++) { - dep = buffer[4 * a + 1]; - val = buffer[4 * a + 3]; + mgroup->customdata = xmgroup; - if (val == MAN_TRANS_C) { - return MAN_TRANS_C; - } - else if (val == MAN_SCALE_C) { - return MAN_SCALE_C; - } - else { - if (val & MAN_ROT_C) { - if (minvalrot == 0 || dep < mindeprot) { - mindeprot = dep; - minvalrot = val; - } - } - else { - if (minval == 0 || dep < mindep) { - mindep = dep; - minval = val; + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + PointerRNA *ptr; + + /* assign operator */ + PropertyRNA *prop_release_confirm = NULL; + PropertyRNA *prop_constraint_axis = NULL; + + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + for (int z = 0; z < 3; z++) { + int constraint[3] = {x != 1, y != 1, z != 1}; + ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL); + if (prop_release_confirm == NULL) { + prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); } + RNA_property_boolean_set(ptr, prop_release_confirm, true); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint); + i++; } } } - - if (minval) - return minval; - else - return minvalrot; } - return 0; } -static const char *manipulator_get_operator_name(int man_val) +static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup) { - if (man_val & MAN_TRANS_C) { - return "TRANSFORM_OT_translate"; - } - else if (man_val == MAN_ROT_T) { - return "TRANSFORM_OT_trackball"; - } - else if (man_val & MAN_ROT_C) { - return "TRANSFORM_OT_rotate"; - } - else if (man_val & MAN_SCALE_C) { - return "TRANSFORM_OT_resize"; - } - - return NULL; -} - -/* return 0; nothing happened */ -int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; ARegion *ar = CTX_wm_region(C); - int constraint_axis[3] = {0, 0, 0}; - int val; - const bool use_planar = RNA_boolean_get(op->ptr, "use_planar_constraint"); - - if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0; - if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0; - - /* Force orientation */ - RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode); - - // find the hotspots first test narrow hotspot - val = manipulator_selectbuf(scene, sa, ar, event->mval, 0.5f * (float)U.tw_hotspot); - if (val) { - wmOperatorType *ot; - PointerRNA props_ptr; - PropertyRNA *prop; - const char *opname; - - // drawflags still global, for drawing call above - drawflags = manipulator_selectbuf(scene, sa, ar, event->mval, 0.2f * (float)U.tw_hotspot); - if (drawflags == 0) drawflags = val; - - /* Planar constraint doesn't make sense for rotation, give other keymaps a chance */ - if ((drawflags & MAN_ROT_C) && use_planar) { - return 0; - } + RegionView3D *rv3d = ar->regiondata; - opname = manipulator_get_operator_name(drawflags); - ot = WM_operatortype_find(opname, true); - WM_operator_properties_create_ptr(&props_ptr, ot); + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; - if (drawflags & MAN_TRANS_C) { - switch (drawflags) { - case MAN_TRANS_C: - break; - case MAN_TRANS_X: - if (use_planar) { - constraint_axis[1] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[0] = 1; - break; - case MAN_TRANS_Y: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[1] = 1; - break; - case MAN_TRANS_Z: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[1] = 1; - } - else - constraint_axis[2] = 1; - break; - } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); - } - else if (drawflags & MAN_SCALE_C) { - switch (drawflags) { - case MAN_SCALE_X: - if (use_planar) { - constraint_axis[1] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[0] = 1; - break; - case MAN_SCALE_Y: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[1] = 1; - break; - case MAN_SCALE_Z: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[1] = 1; + struct TransformBounds tbounds; + + if ((calc_manipulator_stats(C, false, &tbounds) == 0) || + equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) + { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + else { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true); + + float dims[3]; + sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); + RNA_float_set_array(mpr->ptr, "dimensions", dims); + mul_v3_fl(dims, 0.5f); + + copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix); + mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min); + mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]); + + PropertyRNA *prop_center_override = NULL; + float center[3]; + float center_global[3]; + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + center[0] = (float)(1 - x) * dims[0]; + for (int y = 0; y < 3; y++) { + center[1] = (float)(1 - y) * dims[1]; + for (int z = 0; z < 3; z++) { + center[2] = (float)(1 - z) * dims[2]; + struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i); + if (prop_center_override == NULL) { + prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); } - else - constraint_axis[2] = 1; - break; - } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); - } - else if (drawflags == MAN_ROT_T) { - /* pass */ - } - else if (drawflags & MAN_ROT_C) { - switch (drawflags) { - case MAN_ROT_X: - constraint_axis[0] = 1; - break; - case MAN_ROT_Y: - constraint_axis[1] = 1; - break; - case MAN_ROT_Z: - constraint_axis[2] = 1; - break; + mul_v3_m4v3(center_global, mpr->matrix_offset, center); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global); + i++; + } } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); } + } +} - /* pass operator properties on to transform operators */ - prop = RNA_struct_find_property(op->ptr, "use_accurate"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop)); - } - prop = RNA_struct_find_property(op->ptr, "release_confirm"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop)); - } - prop = RNA_struct_find_property(op->ptr, "constraint_orientation"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(&props_ptr, prop, RNA_property_enum_get(op->ptr, prop)); - } +static void WIDGETGROUP_xform_cage_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, VIEW3D_WGT_xform_cage); +} - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); - WM_operator_properties_free(&props_ptr); +static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; + const WorkSpace *workspace = CTX_wm_workspace(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + if (ob && workspace->object_mode & OB_MODE_EDIT) { + copy_m4_m4(mpr->matrix_space, ob->obmat); + } + else { + unit_m4(mpr->matrix_space); } - /* after transform, restore drawflags */ - drawflags = 0xFFFF; +} + +void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Cage"; + wgt->idname = "VIEW3D_WGT_xform_cage"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - return val; + wgt->poll = WIDGETGROUP_xform_cage_poll; + wgt->setup = WIDGETGROUP_xform_cage_setup; + wgt->refresh = WIDGETGROUP_xform_cage_refresh; + wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe; + wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; } +/** \} */ |