Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_gizmo.c
- This file was added.
| /* | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License | |||||
| * as published by the Free Software Foundation; either version 2 | |||||
| * of the License, or (at your option) any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU General Public License | |||||
| * along with this program; if not, write to the Free Software Foundation, | |||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| */ | |||||
| /** \file | |||||
| * \ingroup edtransform | |||||
| * | |||||
| * \name 3D Transform Gizmo | |||||
| * | |||||
| * Used for 3D View | |||||
| */ | |||||
| #include <float.h> | |||||
| #include "DNA_armature_types.h" | |||||
| #include "DNA_gpencil_types.h" | |||||
| #include "DNA_lattice_types.h" | |||||
| #include "DNA_meta_types.h" | |||||
| #include "BLI_math.h" | |||||
| #include "BKE_action.h" | |||||
| #include "BKE_armature.h" | |||||
| #include "BKE_context.h" | |||||
| #include "BKE_curve.h" | |||||
| #include "BKE_editmesh.h" | |||||
| #include "BKE_gpencil.h" | |||||
| #include "BKE_layer.h" | |||||
| #include "BKE_object.h" | |||||
| #include "BKE_paint.h" | |||||
| #include "BKE_pointcache.h" | |||||
| #include "BKE_scene.h" | |||||
| #include "WM_api.h" | |||||
| #include "WM_message.h" | |||||
| #include "wm.h" | |||||
| #include "ED_armature.h" | |||||
| #include "ED_gizmo_library.h" | |||||
| #include "ED_gpencil.h" | |||||
| #include "ED_object.h" | |||||
| #include "ED_particle.h" | |||||
| #include "UI_interface.h" | |||||
| #include "UI_resources.h" | |||||
| #include "RNA_access.h" | |||||
| #include "MEM_guardedalloc.h" | |||||
| #include "GPU_state.h" | |||||
| /* local module include */ | |||||
| #include "transform.h" | |||||
| #include "transform_convert.h" | |||||
| #include "transform_gizmo.h" | |||||
| #include "transform_snap.h" | |||||
| /* threshold for testing view aligned gizmo axis */ | |||||
| static struct { | |||||
| float min, max; | |||||
| } g_tw_axis_range[2] = { | |||||
| /* Regular range */ | |||||
| {0.02f, 0.1f}, | |||||
| /* Use a different range because we flip the dot product, | |||||
| * also the view aligned planes are harder to see so hiding early is preferred. */ | |||||
| {0.175f, 0.25f}, | |||||
| }; | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Utilities | |||||
| * \{ */ | |||||
| /* could move into BLI_math however this is only useful for display/editing purposes */ | |||||
| static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle) | |||||
| { | |||||
| /* X/Y are arbitrary axes, most importantly Z is the axis of rotation. */ | |||||
| float cross_vec[3]; | |||||
| float quat[4]; | |||||
| /* this is an un-scientific method to get a vector to cross with | |||||
| * XYZ intentionally YZX */ | |||||
| cross_vec[0] = axis[1]; | |||||
| cross_vec[1] = axis[2]; | |||||
| cross_vec[2] = axis[0]; | |||||
| /* X-axis */ | |||||
| cross_v3_v3v3(gmat[0], cross_vec, axis); | |||||
| normalize_v3(gmat[0]); | |||||
| axis_angle_to_quat(quat, axis, angle); | |||||
| mul_qt_v3(quat, gmat[0]); | |||||
| /* Y-axis */ | |||||
| axis_angle_to_quat(quat, axis, M_PI_2); | |||||
| copy_v3_v3(gmat[1], gmat[0]); | |||||
| mul_qt_v3(quat, gmat[1]); | |||||
| /* Z-axis */ | |||||
| copy_v3_v3(gmat[2], axis); | |||||
| normalize_m3(gmat); | |||||
| } | |||||
| static bool test_rotmode_euler(short rotmode) | |||||
| { | |||||
| return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; | |||||
| } | |||||
| /* **************** Preparation Stuff **************** */ | |||||
| static void reset_tw_center(struct TransformBounds *tbounds) | |||||
| { | |||||
| INIT_MINMAX(tbounds->min, tbounds->max); | |||||
| zero_v3(tbounds->center); | |||||
| for (int i = 0; i < 3; i++) { | |||||
| tbounds->axis_min[i] = +FLT_MAX; | |||||
| tbounds->axis_max[i] = -FLT_MAX; | |||||
| } | |||||
| } | |||||
| /* 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); | |||||
| 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]); | |||||
| } | |||||
| } | |||||
| static void calc_tw_center_with_matrix(struct TransformBounds *tbounds, | |||||
| const float co[3], | |||||
| const bool use_matrix, | |||||
| const float matrix[4][4]) | |||||
| { | |||||
| float co_world[3]; | |||||
| if (use_matrix) { | |||||
| mul_v3_m4v3(co_world, matrix, co); | |||||
| co = co_world; | |||||
| } | |||||
| calc_tw_center(tbounds, co); | |||||
| } | |||||
| static void protectflag_to_drawflags(short protectflag, short *drawflags) | |||||
| { | |||||
| if (protectflag & OB_LOCK_LOCX) { | |||||
| *drawflags &= ~MAN_TRANS_X; | |||||
| } | |||||
| if (protectflag & OB_LOCK_LOCY) { | |||||
| *drawflags &= ~MAN_TRANS_Y; | |||||
| } | |||||
| if (protectflag & OB_LOCK_LOCZ) { | |||||
| *drawflags &= ~MAN_TRANS_Z; | |||||
| } | |||||
| if (protectflag & OB_LOCK_ROTX) { | |||||
| *drawflags &= ~MAN_ROT_X; | |||||
| } | |||||
| if (protectflag & OB_LOCK_ROTY) { | |||||
| *drawflags &= ~MAN_ROT_Y; | |||||
| } | |||||
| if (protectflag & OB_LOCK_ROTZ) { | |||||
| *drawflags &= ~MAN_ROT_Z; | |||||
| } | |||||
| if (protectflag & OB_LOCK_SCALEX) { | |||||
| *drawflags &= ~MAN_SCALE_X; | |||||
| } | |||||
| if (protectflag & OB_LOCK_SCALEY) { | |||||
| *drawflags &= ~MAN_SCALE_Y; | |||||
| } | |||||
| if (protectflag & OB_LOCK_SCALEZ) { | |||||
| *drawflags &= ~MAN_SCALE_Z; | |||||
| } | |||||
| } | |||||
| /* for pose mode */ | |||||
| static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, | |||||
| const bPoseChannel *pchan, | |||||
| short orientation_index) | |||||
| { | |||||
| /* Protect-flags apply to local space in pose mode, so only let them influence axis | |||||
| * visibility if we show the global orientation, otherwise it's confusing. */ | |||||
| if (orientation_index == V3D_ORIENT_LOCAL) { | |||||
| protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); | |||||
| } | |||||
| } | |||||
| /* For editmode. */ | |||||
| static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo) | |||||
| { | |||||
| if (ebo->flag & BONE_EDITMODE_LOCKED) { | |||||
| protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Return false when no gimbal for selection. | |||||
| */ | |||||
| bool gimbal_axis(Object *ob, float gmat[3][3]) | |||||
| { | |||||
| if (ob->mode & OB_MODE_POSE) { | |||||
| bPoseChannel *pchan = BKE_pose_channel_active(ob); | |||||
| if (pchan) { | |||||
| float mat[3][3], tmat[3][3], obmat[3][3]; | |||||
| if (test_rotmode_euler(pchan->rotmode)) { | |||||
| eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); | |||||
| } | |||||
| else if (pchan->rotmode == ROT_MODE_AXISANGLE) { | |||||
| axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); | |||||
| } | |||||
| else { /* quat */ | |||||
| return 0; | |||||
| } | |||||
| /* apply bone transformation */ | |||||
| mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); | |||||
| if (pchan->parent) { | |||||
| float parent_mat[3][3]; | |||||
| copy_m3_m4(parent_mat, | |||||
| (pchan->bone->flag & BONE_HINGE) ? pchan->parent->bone->arm_mat : | |||||
| pchan->parent->pose_mat); | |||||
| mul_m3_m3m3(mat, parent_mat, tmat); | |||||
| /* needed if object transformation isn't identity */ | |||||
| copy_m3_m4(obmat, ob->obmat); | |||||
| mul_m3_m3m3(gmat, obmat, mat); | |||||
| } | |||||
| else { | |||||
| /* needed if object transformation isn't identity */ | |||||
| copy_m3_m4(obmat, ob->obmat); | |||||
| mul_m3_m3m3(gmat, obmat, tmat); | |||||
| } | |||||
| normalize_m3(gmat); | |||||
| return 1; | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (test_rotmode_euler(ob->rotmode)) { | |||||
| eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); | |||||
| } | |||||
| else if (ob->rotmode == ROT_MODE_AXISANGLE) { | |||||
| axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); | |||||
| } | |||||
| else { /* quat */ | |||||
| return 0; | |||||
| } | |||||
| if (ob->parent) { | |||||
| float parent_mat[3][3]; | |||||
| copy_m3_m4(parent_mat, ob->parent->obmat); | |||||
| normalize_m3(parent_mat); | |||||
| mul_m3_m3m3(gmat, parent_mat, gmat); | |||||
| } | |||||
| return 1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| /* centroid, boundbox, of selection */ | |||||
| /* returns total items selected */ | |||||
| int ED_transform_calc_gizmo_stats(const bContext *C, | |||||
| const struct TransformCalcParams *params, | |||||
| struct TransformBounds *tbounds) | |||||
| { | |||||
| ScrArea *area = CTX_wm_area(C); | |||||
| ARegion *region = CTX_wm_region(C); | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| /* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh(). | |||||
| * Is it fine to possibly evaluate dependency graph here? */ | |||||
| Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| View3D *v3d = area->spacedata.first; | |||||
| Object *obedit = CTX_data_edit_object(C); | |||||
| RegionView3D *rv3d = region->regiondata; | |||||
| Base *base; | |||||
| Object *ob = OBACT(view_layer); | |||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | |||||
| const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); | |||||
| const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); | |||||
| int a, totsel = 0; | |||||
| const int pivot_point = scene->toolsettings->transform_pivot_point; | |||||
| const short orient_index = params->orientation_index ? | |||||
| (params->orientation_index - 1) : | |||||
| BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT); | |||||
| /* transform widget matrix */ | |||||
| unit_m4(rv3d->twmat); | |||||
| unit_m3(rv3d->tw_axis_matrix); | |||||
| zero_v3(rv3d->tw_axis_min); | |||||
| zero_v3(rv3d->tw_axis_max); | |||||
| rv3d->twdrawflag = 0xFFFF; | |||||
| /* global, local or normal orientation? | |||||
| * if we could check 'totsel' now, this should be skipped with no selection. */ | |||||
| if (ob) { | |||||
| float mat[3][3]; | |||||
| ED_transform_calc_orientation_from_type_ex( | |||||
| scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat); | |||||
| copy_m4_m3(rv3d->twmat, mat); | |||||
| } | |||||
| /* transform widget centroid/center */ | |||||
| reset_tw_center(tbounds); | |||||
| copy_m3_m4(tbounds->axis, rv3d->twmat); | |||||
| if (params->use_local_axis && (ob && ob->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); | |||||
| } | |||||
| if (is_gp_edit) { | |||||
| float diff_mat[4][4]; | |||||
| const bool use_mat_local = true; | |||||
| LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { | |||||
| /* only editable and visible layers are considered */ | |||||
| if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { | |||||
| /* calculate difference matrix */ | |||||
| BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); | |||||
| LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { | |||||
| /* skip strokes that are invalid for current view */ | |||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) { | |||||
| continue; | |||||
| } | |||||
| if (is_curve_edit) { | |||||
| if (gps->editcurve == NULL) { | |||||
| continue; | |||||
| } | |||||
| bGPDcurve *gpc = gps->editcurve; | |||||
| if (gpc->flag & GP_CURVE_SELECT) { | |||||
| for (uint32_t i = 0; i < gpc->tot_curve_points; i++) { | |||||
| bGPDcurve_point *gpc_pt = &gpc->curve_points[i]; | |||||
| BezTriple *bezt = &gpc_pt->bezt; | |||||
| if (gpc_pt->flag & GP_CURVE_POINT_SELECT) { | |||||
| for (uint32_t j = 0; j < 3; j++) { | |||||
| if (BEZT_ISSEL_IDX(bezt, j)) { | |||||
| calc_tw_center_with_matrix(tbounds, bezt->vec[j], use_mat_local, diff_mat); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* we're only interested in selected points here... */ | |||||
| if (gps->flag & GP_STROKE_SELECT) { | |||||
| bGPDspoint *pt; | |||||
| int i; | |||||
| /* Change selection status of all points, then make the stroke match */ | |||||
| for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { | |||||
| if (pt->flag & GP_SPOINT_SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, &pt->x, use_mat_local, diff_mat); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* selection center */ | |||||
| if (totsel) { | |||||
| mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ | |||||
| } | |||||
| } | |||||
| else if (obedit) { | |||||
| #define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \ | |||||
| { \ | |||||
| invert_m4_m4(obedit->imat, obedit->obmat); \ | |||||
| uint objects_len = 0; \ | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( \ | |||||
| view_layer, CTX_wm_view3d(C), &objects_len); \ | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { \ | |||||
| Object *ob_iter = objects[ob_index]; \ | |||||
| const bool use_mat_local = (ob_iter != obedit); | |||||
| #define FOREACH_EDIT_OBJECT_END() \ | |||||
| } \ | |||||
| MEM_freeN(objects); \ | |||||
| } \ | |||||
| ((void)0) | |||||
| ob = obedit; | |||||
| if (obedit->type == OB_MESH) { | |||||
| FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { | |||||
| BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | |||||
| BMesh *bm = em_iter->bm; | |||||
| if (bm->totvertsel == 0) { | |||||
| continue; | |||||
| } | |||||
| BMVert *eve; | |||||
| BMIter iter; | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); | |||||
| } | |||||
| BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | |||||
| if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | |||||
| calc_tw_center_with_matrix(tbounds, eve->co, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| FOREACH_EDIT_OBJECT_END(); | |||||
| } /* end editmesh */ | |||||
| else if (obedit->type == OB_ARMATURE) { | |||||
| FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { | |||||
| bArmature *arm = ob_iter->data; | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); | |||||
| } | |||||
| LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { | |||||
| if (EBONE_VISIBLE(arm, ebo)) { | |||||
| if (ebo->flag & BONE_TIPSEL) { | |||||
| calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| if ((ebo->flag & BONE_ROOTSEL) && | |||||
| /* don't include same point multiple times */ | |||||
| ((ebo->flag & BONE_CONNECTED) && (ebo->parent != NULL) && | |||||
| (ebo->parent->flag & BONE_TIPSEL) && EBONE_VISIBLE(arm, ebo->parent)) == 0) { | |||||
| calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { | |||||
| protectflag_to_drawflags_ebone(rv3d, ebo); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| FOREACH_EDIT_OBJECT_END(); | |||||
| } | |||||
| else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { | |||||
| FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { | |||||
| Curve *cu = ob_iter->data; | |||||
| Nurb *nu; | |||||
| BezTriple *bezt; | |||||
| BPoint *bp; | |||||
| ListBase *nurbs = BKE_curve_editNurbs_get(cu); | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); | |||||
| } | |||||
| nu = nurbs->first; | |||||
| while (nu) { | |||||
| if (nu->type == CU_BEZIER) { | |||||
| bezt = nu->bezt; | |||||
| a = nu->pntsu; | |||||
| while (a--) { | |||||
| /* exceptions | |||||
| * if handles are hidden then only check the center points. | |||||
| * If the center knot is selected then only use this as the center point. | |||||
| */ | |||||
| if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) { | |||||
| if (bezt->f2 & SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| else if (bezt->f2 & SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| else { | |||||
| if (bezt->f1 & SELECT) { | |||||
| const float *co = bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]; | |||||
| calc_tw_center_with_matrix(tbounds, co, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| if (bezt->f3 & SELECT) { | |||||
| const float *co = bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]; | |||||
| calc_tw_center_with_matrix(tbounds, co, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| bezt++; | |||||
| } | |||||
| } | |||||
| else { | |||||
| bp = nu->bp; | |||||
| a = nu->pntsu * nu->pntsv; | |||||
| while (a--) { | |||||
| if (bp->f1 & SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| bp++; | |||||
| } | |||||
| } | |||||
| nu = nu->next; | |||||
| } | |||||
| } | |||||
| FOREACH_EDIT_OBJECT_END(); | |||||
| } | |||||
| else if (obedit->type == OB_MBALL) { | |||||
| FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { | |||||
| MetaBall *mb = (MetaBall *)ob_iter->data; | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); | |||||
| } | |||||
| LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { | |||||
| if (ml->flag & SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| FOREACH_EDIT_OBJECT_END(); | |||||
| } | |||||
| else if (obedit->type == OB_LATTICE) { | |||||
| FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) { | |||||
| Lattice *lt = ((Lattice *)ob_iter->data)->editlatt->latt; | |||||
| BPoint *bp = lt->def; | |||||
| a = lt->pntsu * lt->pntsv * lt->pntsw; | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat); | |||||
| } | |||||
| while (a--) { | |||||
| if (bp->f1 & SELECT) { | |||||
| calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local); | |||||
| totsel++; | |||||
| } | |||||
| bp++; | |||||
| } | |||||
| } | |||||
| FOREACH_EDIT_OBJECT_END(); | |||||
| } | |||||
| #undef FOREACH_EDIT_OBJECT_BEGIN | |||||
| #undef FOREACH_EDIT_OBJECT_END | |||||
| /* selection center */ | |||||
| if (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)) { | |||||
| invert_m4_m4(ob->imat, ob->obmat); | |||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_object_pose_array_get(view_layer, v3d, &objects_len); | |||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *ob_iter = objects[ob_index]; | |||||
| const bool use_mat_local = (ob_iter != ob); | |||||
| bPoseChannel *pchan; | |||||
| /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ | |||||
| const int mode = TFM_ROTATION; | |||||
| const int totsel_iter = transform_convert_pose_transflags_update( | |||||
| ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL); | |||||
| if (totsel_iter) { | |||||
| float mat_local[4][4]; | |||||
| if (use_mat_local) { | |||||
| mul_m4_m4m4(mat_local, ob->imat, ob_iter->obmat); | |||||
| } | |||||
| /* use channels to get stats */ | |||||
| for (pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { | |||||
| Bone *bone = pchan->bone; | |||||
| if (bone && (bone->flag & BONE_TRANSFORM)) { | |||||
| calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); | |||||
| protectflag_to_drawflags_pchan(rv3d, pchan, orient_index); | |||||
| } | |||||
| } | |||||
| totsel += totsel_iter; | |||||
| } | |||||
| } | |||||
| MEM_freeN(objects); | |||||
| if (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)) { | |||||
| if (ob->mode & OB_MODE_SCULPT) { | |||||
| totsel = 1; | |||||
| calc_tw_center_with_matrix(tbounds, ob->sculpt->pivot_pos, false, ob->obmat); | |||||
| 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_PARTICLE_EDIT) { | |||||
| PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); | |||||
| PTCacheEditPoint *point; | |||||
| PTCacheEditKey *ek; | |||||
| int k; | |||||
| if (edit) { | |||||
| point = edit->points; | |||||
| for (a = 0; a < edit->totpoint; a++, point++) { | |||||
| if (point->flag & PEP_HIDE) { | |||||
| continue; | |||||
| } | |||||
| for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { | |||||
| if (ek->flag & PEK_SELECT) { | |||||
| calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); | |||||
| totsel++; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* selection center */ | |||||
| if (totsel) { | |||||
| mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* we need the one selected object, if its not active */ | |||||
| base = BASACT(view_layer); | |||||
| ob = OBACT(view_layer); | |||||
| if (base && ((base->flag & BASE_SELECTED) == 0)) { | |||||
| ob = NULL; | |||||
| } | |||||
| for (base = view_layer->object_bases.first; base; base = base->next) { | |||||
| if (!BASE_SELECTED_EDITABLE(v3d, base)) { | |||||
| continue; | |||||
| } | |||||
| if (ob == NULL) { | |||||
| ob = base->object; | |||||
| } | |||||
| /* Get the boundbox out of the evaluated object. */ | |||||
| const BoundBox *bb = NULL; | |||||
| if (params->use_only_center == false) { | |||||
| bb = BKE_object_boundbox_get(base->object); | |||||
| } | |||||
| if (params->use_only_center || (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, bb->vec[j]); | |||||
| calc_tw_center(tbounds, co); | |||||
| } | |||||
| } | |||||
| /* Protect-flags apply to world space in object mode, so only let them influence axis | |||||
| * visibility if we show the global orientation, otherwise it's confusing. */ | |||||
| if (orient_index == V3D_ORIENT_GLOBAL) { | |||||
| protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); | |||||
| } | |||||
| totsel++; | |||||
| } | |||||
| /* selection center */ | |||||
| if (totsel) { | |||||
| mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ | |||||
| } | |||||
| } | |||||
| if (totsel == 0) { | |||||
| unit_m4(rv3d->twmat); | |||||
| } | |||||
| else { | |||||
| 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); | |||||
| } | |||||
| return totsel; | |||||
| } | |||||
| void gizmo_prepare_mat(const bContext *C, | |||||
| RegionView3D *rv3d, | |||||
| const struct TransformBounds *tbounds) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| switch (scene->toolsettings->transform_pivot_point) { | |||||
| case V3D_AROUND_CENTER_BOUNDS: | |||||
| case V3D_AROUND_ACTIVE: { | |||||
| mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); | |||||
| if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { | |||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | |||||
| if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { | |||||
| /* pass */ | |||||
| } | |||||
| else { | |||||
| Object *ob = OBACT(view_layer); | |||||
| if (ob != NULL) { | |||||
| if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { | |||||
| SculptSession *ss = ob->sculpt; | |||||
| copy_v3_v3(rv3d->twmat[3], ss->pivot_pos); | |||||
| } | |||||
| else { | |||||
| ED_object_calc_active_center(ob, false, rv3d->twmat[3]); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| break; | |||||
| } | |||||
| case V3D_AROUND_LOCAL_ORIGINS: | |||||
| case V3D_AROUND_CENTER_MEDIAN: | |||||
| copy_v3_v3(rv3d->twmat[3], tbounds->center); | |||||
| break; | |||||
| case V3D_AROUND_CURSOR: | |||||
| copy_v3_v3(rv3d->twmat[3], scene->cursor.location); | |||||
| break; | |||||
| } | |||||
| } | |||||
| uint gizmo_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; | |||||
| } | |||||
| bool gizmo_is_axis_visible(const RegionView3D *rv3d, | |||||
| const int twtype, | |||||
| const float idot[3], | |||||
| const int axis_type, | |||||
| const int axis_idx) | |||||
| { | |||||
| if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) { | |||||
| bool is_plane = false; | |||||
| const uint aidx_norm = gizmo_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 < g_tw_axis_range[is_plane].min) { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE)) || | |||||
| (axis_type == MAN_AXES_ROTATE && !(twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE)) || | |||||
| (axis_type == MAN_AXES_SCALE && !(twtype & V3D_GIZMO_SHOW_OBJECT_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 && (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0); | |||||
| case MAN_AXIS_TRANS_XY: | |||||
| return (rv3d->twdrawflag & MAN_TRANS_X && rv3d->twdrawflag & MAN_TRANS_Y && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| case MAN_AXIS_TRANS_YZ: | |||||
| return (rv3d->twdrawflag & MAN_TRANS_Y && rv3d->twdrawflag & MAN_TRANS_Z && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| case MAN_AXIS_TRANS_ZX: | |||||
| return (rv3d->twdrawflag & MAN_TRANS_Z && rv3d->twdrawflag & MAN_TRANS_X && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| case MAN_AXIS_SCALE_XY: | |||||
| return (rv3d->twdrawflag & MAN_SCALE_X && rv3d->twdrawflag & MAN_SCALE_Y && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| case MAN_AXIS_SCALE_YZ: | |||||
| return (rv3d->twdrawflag & MAN_SCALE_Y && rv3d->twdrawflag & MAN_SCALE_Z && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| case MAN_AXIS_SCALE_ZX: | |||||
| return (rv3d->twdrawflag & MAN_SCALE_Z && rv3d->twdrawflag & MAN_SCALE_X && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 && | |||||
| (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void gizmo_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; | |||||
| if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { | |||||
| /* Never fade rotation rings. */ | |||||
| /* trackball rotation axis is a special case, we only draw a slight overlay */ | |||||
| alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f; | |||||
| } | |||||
| else { | |||||
| bool is_plane = false; | |||||
| const int axis_idx_norm = gizmo_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) { | |||||
| const float idot_min = g_tw_axis_range[is_plane].min; | |||||
| const float idot_max = g_tw_axis_range[is_plane].max; | |||||
| float idot_axis = idot[axis_idx_norm]; | |||||
| if (is_plane) { | |||||
| idot_axis = 1.0f - idot_axis; | |||||
| } | |||||
| alpha_fac = ((idot_axis > idot_max) ? 1.0f : | |||||
| (idot_axis < idot_min) ? 0.0f : | |||||
| ((idot_axis - idot_min) / (idot_max - idot_min))); | |||||
| } | |||||
| else { | |||||
| alpha_fac = 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: | |||||
| UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, r_col); | |||||
| break; | |||||
| } | |||||
| copy_v4_v4(r_col_hi, r_col); | |||||
| r_col[3] = alpha * alpha_fac; | |||||
| r_col_hi[3] = alpha_hi * alpha_fac; | |||||
| } | |||||
| void drawDial3d(const TransInfo *t) | |||||
| { | |||||
| if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) { | |||||
| if (t->options & CTX_PAINT_CURVE) { | |||||
| /* Matrices are in the screen space. Not supported. */ | |||||
| return; | |||||
| } | |||||
| wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map); | |||||
| if (gz == NULL) { | |||||
| /* We only draw Dial3d if the operator has been called by a gizmo. */ | |||||
| return; | |||||
| } | |||||
| float mat_basis[4][4]; | |||||
| float mat_final[4][4]; | |||||
| float color[4]; | |||||
| float increment = 0.0f; | |||||
| float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f; | |||||
| float scale = UI_DPI_FAC * U.gizmo_size; | |||||
| int axis_idx; | |||||
| const TransCon *tc = &(t->con); | |||||
| if (tc->mode & CON_APPLY) { | |||||
| if (tc->mode & CON_AXIS0) { | |||||
| axis_idx = MAN_AXIS_ROT_X; | |||||
| negate_v3_v3(mat_basis[2], t->spacemtx[0]); | |||||
| } | |||||
| else if (tc->mode & CON_AXIS1) { | |||||
| axis_idx = MAN_AXIS_ROT_Y; | |||||
| negate_v3_v3(mat_basis[2], t->spacemtx[1]); | |||||
| } | |||||
| else { | |||||
| BLI_assert((tc->mode & CON_AXIS2) != 0); | |||||
| axis_idx = MAN_AXIS_ROT_Z; | |||||
| negate_v3_v3(mat_basis[2], t->spacemtx[2]); | |||||
| } | |||||
| } | |||||
| else { | |||||
| axis_idx = MAN_AXIS_ROT_C; | |||||
| copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); | |||||
| scale *= 1.2f; | |||||
| line_with -= 1.0f; | |||||
| } | |||||
| copy_v3_v3(mat_basis[3], t->center_global); | |||||
| mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]); | |||||
| if (ED_view3d_win_to_3d_on_plane( | |||||
| t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) { | |||||
| sub_v3_v3(mat_basis[1], mat_basis[3]); | |||||
| normalize_v3(mat_basis[1]); | |||||
| cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]); | |||||
| } | |||||
| else { | |||||
| /* The plane and the mouse direction are parallel. | |||||
| * Calculate a matrix orthogonal to the axis. */ | |||||
| ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]); | |||||
| } | |||||
| mat_basis[0][3] = 0.0f; | |||||
| mat_basis[1][3] = 0.0f; | |||||
| mat_basis[2][3] = 0.0f; | |||||
| mat_basis[3][3] = 1.0f; | |||||
| copy_m4_m4(mat_final, mat_basis); | |||||
| scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]); | |||||
| mul_mat3_m4_fl(mat_final, scale); | |||||
| if (activeSnap(t) && (!transformModeUseSnap(t) || | |||||
| (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) { | |||||
| increment = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0]; | |||||
| } | |||||
| BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END); | |||||
| gizmo_get_axis_color(axis_idx, NULL, color, color); | |||||
| GPU_depth_test(GPU_DEPTH_NONE); | |||||
| GPU_blend(GPU_BLEND_ALPHA); | |||||
| GPU_line_smooth(true); | |||||
| ED_gizmotypes_dial_3d_draw_util(mat_basis, | |||||
| mat_final, | |||||
| line_with, | |||||
| color, | |||||
| false, | |||||
| &(struct Dial3dParams){ | |||||
| .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE, | |||||
| .angle_delta = t->values_final[0], | |||||
| .angle_increment = increment, | |||||
| }); | |||||
| GPU_line_smooth(false); | |||||
| GPU_depth_test(GPU_DEPTH_LESS_EQUAL); | |||||
| GPU_blend(GPU_BLEND_NONE); | |||||
| } | |||||
| } | |||||
| void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, | |||||
| struct wmMsgBus *mbus, | |||||
| Scene *scene, | |||||
| bScreen *screen, | |||||
| ScrArea *area, | |||||
| ARegion *region, | |||||
| const int orient_flag, | |||||
| const bool use_twtype_refresh, | |||||
| const void *type_fn) | |||||
| { | |||||
| /* Subscribe to view properties */ | |||||
| wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { | |||||
| .owner = region, | |||||
| .user_data = gzgroup->parent_gzmap, | |||||
| .notify = WM_gizmo_do_msg_notify_tag_refresh, | |||||
| }; | |||||
| TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag(scene, | |||||
| orient_flag); | |||||
| PointerRNA orient_ref_ptr; | |||||
| RNA_pointer_create(&scene->id, &RNA_TransformOrientationSlot, orient_slot, &orient_ref_ptr); | |||||
| const ToolSettings *ts = scene->toolsettings; | |||||
| PointerRNA scene_ptr; | |||||
| RNA_id_pointer_create(&scene->id, &scene_ptr); | |||||
| { | |||||
| extern PropertyRNA rna_Scene_transform_orientation_slots; | |||||
| const PropertyRNA *props[] = { | |||||
| &rna_Scene_transform_orientation_slots, | |||||
| }; | |||||
| for (int i = 0; i < ARRAY_SIZE(props); i++) { | |||||
| WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| } | |||||
| if ((ts->transform_pivot_point == V3D_AROUND_CURSOR) || | |||||
| (orient_slot->type == V3D_ORIENT_CURSOR)) { | |||||
| /* We could be more specific here, for now subscribe to any cursor change. */ | |||||
| PointerRNA cursor_ptr; | |||||
| RNA_pointer_create(&scene->id, &RNA_View3DCursor, &scene->cursor, &cursor_ptr); | |||||
| WM_msg_subscribe_rna(mbus, &cursor_ptr, NULL, &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| { | |||||
| extern PropertyRNA rna_TransformOrientationSlot_type; | |||||
| extern PropertyRNA rna_TransformOrientationSlot_use; | |||||
| const PropertyRNA *props[] = { | |||||
| &rna_TransformOrientationSlot_type, | |||||
| &rna_TransformOrientationSlot_use, | |||||
| }; | |||||
| for (int i = 0; i < ARRAY_SIZE(props); i++) { | |||||
| if (props[i]) { | |||||
| WM_msg_subscribe_rna( | |||||
| mbus, &orient_ref_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| } | |||||
| } | |||||
| PointerRNA toolsettings_ptr; | |||||
| RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr); | |||||
| if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) { | |||||
| extern PropertyRNA rna_ToolSettings_transform_pivot_point; | |||||
| const PropertyRNA *props[] = { | |||||
| &rna_ToolSettings_transform_pivot_point, | |||||
| }; | |||||
| for (int i = 0; i < ARRAY_SIZE(props); i++) { | |||||
| WM_msg_subscribe_rna( | |||||
| mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| } | |||||
| { | |||||
| extern PropertyRNA rna_ToolSettings_workspace_tool_type; | |||||
| const PropertyRNA *props[] = { | |||||
| &rna_ToolSettings_workspace_tool_type, | |||||
| }; | |||||
| for (int i = 0; i < ARRAY_SIZE(props); i++) { | |||||
| WM_msg_subscribe_rna( | |||||
| mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| } | |||||
| PointerRNA view3d_ptr; | |||||
| RNA_pointer_create(&screen->id, &RNA_SpaceView3D, area->spacedata.first, &view3d_ptr); | |||||
| if (type_fn == VIEW3D_GGT_xform_gizmo) { | |||||
| if (use_twtype_refresh) { | |||||
| extern PropertyRNA rna_SpaceView3D_show_gizmo_object_translate; | |||||
| extern PropertyRNA rna_SpaceView3D_show_gizmo_object_rotate; | |||||
| extern PropertyRNA rna_SpaceView3D_show_gizmo_object_scale; | |||||
| const PropertyRNA *props[] = { | |||||
| &rna_SpaceView3D_show_gizmo_object_translate, | |||||
| &rna_SpaceView3D_show_gizmo_object_rotate, | |||||
| &rna_SpaceView3D_show_gizmo_object_scale, | |||||
| }; | |||||
| for (int i = 0; i < ARRAY_SIZE(props); i++) { | |||||
| WM_msg_subscribe_rna(mbus, &view3d_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (type_fn == VIEW3D_GGT_xform_cage) { | |||||
| /* pass */ | |||||
| } | |||||
| else if (type_fn == VIEW3D_GGT_xform_shear) { | |||||
| /* pass */ | |||||
| } | |||||
| else { | |||||
| BLI_assert(0); | |||||
| } | |||||
| WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh); | |||||
| WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh); | |||||
| } | |||||
| /** \} */ | |||||