From 968ecf6f8b887bcbf4109532c6e9bb1375ee9907 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 21 Apr 2023 20:07:05 +0200 Subject: [PATCH] Fix #106993: Slowness with Orbiting around select + Mesh Symmetry The issue happens because the algorithm used to calculate the center of the selection first needs to create a TransData array. In this array, the code calculates the "mirrored" elements which can be quite slow in dense meshes. The solution is replace this slow algorithm used for calculating the pivot point with the fast algorithm used to calculate the position of transform gizmos. Pull Request: https://projects.blender.org/blender/blender/pulls/107203 --- source/blender/editors/include/ED_transform.h | 7 +- .../space_view3d/view3d_gizmo_tool_generic.c | 4 +- .../editors/space_view3d/view3d_navigate.cc | 2 +- .../editors/transform/transform_gizmo_3d.cc | 467 +++++++++++------- .../transform/transform_gizmo_3d_cage.cc | 2 +- .../transform/transform_gizmo_3d_shear.cc | 2 +- .../transform/transform_gizmo_extrude_3d.c | 7 +- 7 files changed, 296 insertions(+), 195 deletions(-) diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 9b1b88a86db..1af4ee05374 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -151,6 +151,10 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene, int pivot_point, float r_mat[3][3]); +bool ED_transform_calc_pivot_pos(const struct bContext *C, + const short pivot_type, + float r_pivot_pos[3]); + /* transform gizmos */ void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt); @@ -201,7 +205,8 @@ struct TransformCalcParams { */ int ED_transform_calc_gizmo_stats(const struct bContext *C, const struct TransformCalcParams *params, - struct TransformBounds *tbounds); + struct TransformBounds *tbounds, + struct RegionView3D *rv3d); /** * Iterates over all the strips and finds the closest snapping candidate of either \a frame_1 or \a diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c index 3519a30e222..e5c90d39385 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c @@ -138,13 +138,15 @@ static void WIDGETGROUP_tool_generic_refresh(const bContext *C, wmGizmoGroup *gz orientation = V3D_ORIENT_GLOBAL; /* dummy, use view. */ } + RegionView3D *rv3d = CTX_wm_region_data(C); struct TransformBounds tbounds; const bool hide = ED_transform_calc_gizmo_stats(C, &(struct TransformCalcParams){ .use_only_center = true, .orientation_index = orientation + 1, }, - &tbounds) == 0; + &tbounds, + rv3d) == 0; WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide); if (hide) { diff --git a/source/blender/editors/space_view3d/view3d_navigate.cc b/source/blender/editors/space_view3d/view3d_navigate.cc index 5ff7af92e09..3affb747611 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.cc +++ b/source/blender/editors/space_view3d/view3d_navigate.cc @@ -304,7 +304,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) } else { /* If there's no selection, `lastofs` is unmodified and last value since static. */ - is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, lastofs, nullptr); + is_set = ED_transform_calc_pivot_pos(C, V3D_AROUND_CENTER_MEDIAN, lastofs); } copy_v3_v3(r_dyn_ofs, lastofs); diff --git a/source/blender/editors/transform/transform_gizmo_3d.cc b/source/blender/editors/transform/transform_gizmo_3d.cc index 594b55992ad..335735047c5 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.cc +++ b/source/blender/editors/transform/transform_gizmo_3d.cc @@ -438,19 +438,6 @@ static void calc_tw_center(TransformBounds *tbounds, const float co[3]) } } -static void calc_tw_center_with_matrix(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) { @@ -484,51 +471,56 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags) } } -/* 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 (ELEM(orientation_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { - 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); - } -} - -int ED_transform_calc_gizmo_stats(const bContext *C, - const TransformCalcParams *params, - TransformBounds *tbounds) +/** + * Run \a user_fn for each coordinate of elements selected in View3D (vertices, particles...). + * \note Each coordinate has the space matrix of the active object. + * + * \param orient_index: A #TransformOrientationSlot.type. Here used for calculating \a r_drawflags. + * \param use_curve_handles: If true, the handles of curves are traversed. + * \param use_only_center: For objects in object mode, defines whether the corners of the bounds or + * just the center are traversed. + * \param user_fn: Callback that runs on each coordinate. + * \param user_data: User argument passed to \a user_fn. + * \param r_mat: Returns the space matrix of the coordinates. + * \param r_drawflags: Drawing flags for gizmos. Usually stored in #RegionView3D::drawflags. + */ +static int gizmo_3d_foreach_selected(const bContext *C, + const short orient_index, + const bool use_curve_handles, + const bool use_only_center, + void (*user_fn)(const float[3], void *), + void *user_data, + const float (**r_mat)[4], + short *r_drawflags) { using namespace blender; + + const auto run_coord_with_matrix = [](const float co[3], + const bool use_matrix, + const float matrix[4][4], + void (*user_fn)(const float[3], void *), + void *user_data) { + float co_world[3]; + if (use_matrix) { + mul_v3_m4v3(co_world, matrix, co); + co = co_world; + } + user_fn(co, user_data); + }; + 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 = static_cast(area->spacedata.first); - RegionView3D *rv3d = static_cast(region->regiondata); Base *base; 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); - BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); @@ -539,42 +531,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } } - tbounds->use_matrix_space = false; - - /* 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 = short(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 | OB_MODE_POSE))) { - float diff_mat[3][3]; - copy_m3_m4(diff_mat, ob->object_to_world); - normalize_m3(diff_mat); - invert_m3(diff_mat); - mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); - normalize_m3(tbounds->axis); - - tbounds->use_matrix_space = true; - copy_m4_m4(tbounds->matrix_space, ob->object_to_world); - } - if (is_gp_edit) { float diff_mat[4][4]; const bool use_mat_local = true; @@ -605,7 +561,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C, 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); + run_coord_with_matrix( + bezt->vec[j], use_mat_local, diff_mat, user_fn, user_data); totsel++; } } @@ -622,7 +579,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* 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); + run_coord_with_matrix(&pt->x, use_mat_local, diff_mat, user_fn, user_data); totsel++; } } @@ -631,11 +588,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } } } - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* centroid! */ - } } else if (obedit) { @@ -676,7 +628,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, 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); + run_coord_with_matrix(eve->co, use_mat_local, mat_local, user_fn, user_data); totsel++; } } @@ -695,18 +647,24 @@ int ED_transform_calc_gizmo_stats(const bContext *C, 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); + run_coord_with_matrix(ebo->tail, use_mat_local, mat_local, user_fn, user_data); totsel++; } if ((ebo->flag & BONE_ROOTSEL) && /* don't include same point multiple times */ ((ebo->flag & BONE_CONNECTED) && (ebo->parent != nullptr) && (ebo->parent->flag & BONE_TIPSEL) && EBONE_VISIBLE(arm, ebo->parent)) == 0) { - calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local); + run_coord_with_matrix(ebo->head, use_mat_local, mat_local, user_fn, user_data); totsel++; - } - if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { - protectflag_to_drawflags_ebone(rv3d, ebo); + + if (r_drawflags) { + if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { + if (ebo->flag & BONE_EDITMODE_LOCKED) { + protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, + r_drawflags); + } + } + } } } } @@ -737,23 +695,24 @@ int ED_transform_calc_gizmo_stats(const bContext *C, */ 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); + run_coord_with_matrix( + bezt->vec[1], use_mat_local, mat_local, user_fn, user_data); totsel++; } } else if (bezt->f2 & SELECT) { - calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local); + run_coord_with_matrix(bezt->vec[1], use_mat_local, mat_local, user_fn, user_data); 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); + const float *co = bezt->vec[!use_curve_handles ? 1 : 0]; + run_coord_with_matrix(co, use_mat_local, mat_local, user_fn, user_data); 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); + const float *co = bezt->vec[!use_curve_handles ? 1 : 2]; + run_coord_with_matrix(co, use_mat_local, mat_local, user_fn, user_data); totsel++; } } @@ -765,7 +724,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, a = nu->pntsu * nu->pntsv; while (a--) { if (bp->f1 & SELECT) { - calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local); + run_coord_with_matrix(bp->vec, use_mat_local, mat_local, user_fn, user_data); totsel++; } bp++; @@ -787,7 +746,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { if (ml->flag & SELECT) { - calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local); + run_coord_with_matrix(&ml->x, use_mat_local, mat_local, user_fn, user_data); totsel++; } } @@ -807,7 +766,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, while (a--) { if (bp->f1 & SELECT) { - calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local); + run_coord_with_matrix(bp->vec, use_mat_local, mat_local, user_fn, user_data); totsel++; } bp++; @@ -832,7 +791,8 @@ int ED_transform_calc_gizmo_stats(const bContext *C, const Span positions = deformation.positions; totsel += selected_points.size(); for (const int point_i : selected_points) { - calc_tw_center_with_matrix(tbounds, positions[point_i], use_mat_local, mat_local.ptr()); + run_coord_with_matrix( + positions[point_i], use_mat_local, mat_local.ptr(), user_fn, user_data); } } FOREACH_EDIT_OBJECT_END(); @@ -840,14 +800,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, #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->object_to_world, tbounds->center); - mul_m4_v3(obedit->object_to_world, tbounds->min); - mul_m4_v3(obedit->object_to_world, tbounds->max); - } } else if (ob && (ob->mode & OB_MODE_POSE)) { invert_m4_m4(ob->world_to_object, ob->object_to_world); @@ -873,27 +825,24 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (!(pchan->bone->flag & BONE_TRANSFORM)) { continue; } - calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); - protectflag_to_drawflags_pchan(rv3d, pchan, orient_index); + run_coord_with_matrix(pchan->pose_head, use_mat_local, mat_local, user_fn, user_data); totsel++; + + if (r_drawflags) { + /* 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 (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { + protectflag_to_drawflags(pchan->protectflag, r_drawflags); + } + } } } MEM_freeN(objects); - - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* centroid! */ - mul_m4_v3(ob->object_to_world, tbounds->center); - mul_m4_v3(ob->object_to_world, tbounds->min); - mul_m4_v3(ob->object_to_world, 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->object_to_world); - mul_m4_v3(ob->object_to_world, tbounds->center); - mul_m4_v3(ob->object_to_world, tbounds->min); - mul_m4_v3(ob->object_to_world, tbounds->max); + run_coord_with_matrix(ob->sculpt->pivot_pos, false, ob->object_to_world, user_fn, user_data); } } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { @@ -911,16 +860,11 @@ int ED_transform_calc_gizmo_stats(const bContext *C, 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); + user_fn((ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co, user_data); totsel++; } } } - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* centroid! */ - } } } else { @@ -944,46 +888,141 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* Get the boundbox out of the evaluated object. */ const BoundBox *bb = nullptr; - if (params->use_only_center == false) { + if (use_only_center == false) { bb = BKE_object_boundbox_get(base->object); } - if (params->use_only_center || (bb == nullptr)) { - calc_tw_center(tbounds, base->object->object_to_world[3]); + if (use_only_center || (bb == nullptr)) { + user_fn(base->object->object_to_world[3], user_data); } else { for (uint j = 0; j < 8; j++) { float co[3]; mul_v3_m4v3(co, base->object->object_to_world, bb->vec[j]); - calc_tw_center(tbounds, co); + user_fn(co, user_data); } } - - if (orient_index == V3D_ORIENT_GLOBAL) { - /* 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. */ - protectflag_to_drawflags(base->object->protectflag & OB_LOCK_LOC, &rv3d->twdrawflag); - } - else if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { - protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); - } totsel++; - } - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* centroid! */ + if (r_drawflags) { + if (orient_index == V3D_ORIENT_GLOBAL) { + /* 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. */ + protectflag_to_drawflags(base->object->protectflag & OB_LOCK_LOC, r_drawflags); + } + else if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) { + protectflag_to_drawflags(base->object->protectflag, r_drawflags); + } + } } } - if (totsel == 0) { - unit_m4(rv3d->twmat); + if (r_mat && ob) { + *r_mat = ob->object_to_world; } - 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; +} + +int ED_transform_calc_gizmo_stats(const bContext *C, + const TransformCalcParams *params, + TransformBounds *tbounds, + RegionView3D *rv3d) +{ + ScrArea *area = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = static_cast(area->spacedata.first); + int 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); + + BKE_view_layer_synced_ensure(scene, view_layer); + Object *ob = BKE_view_layer_active_object_get(view_layer); + Object *obedit = OBEDIT_FROM_OBACT(ob); + if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) { + Object *obpose = BKE_object_pose_armature_get(ob); + if (obpose != nullptr) { + ob = obpose; + } + } + + tbounds->use_matrix_space = false; + unit_m3(tbounds->axis); + + /* 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_m3_m3(tbounds->axis, mat); + } + + reset_tw_center(tbounds); + + if (rv3d) { + /* transform widget centroid/center */ + copy_m4_m3(rv3d->twmat, tbounds->axis); + rv3d->twdrawflag = short(0xFFFF); + } + + if (params->use_local_axis && (ob && ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) { + float diff_mat[3][3]; + copy_m3_m4(diff_mat, ob->object_to_world); + normalize_m3(diff_mat); + invert_m3(diff_mat); + mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); + normalize_m3(tbounds->axis); + + tbounds->use_matrix_space = true; + copy_m4_m4(tbounds->matrix_space, ob->object_to_world); + } + + const auto gizmo_3d_tbounds_calc_fn = [](const float co[3], void *data) { + TransformBounds *tbounds = static_cast(data); + calc_tw_center(tbounds, co); + }; + + totsel = gizmo_3d_foreach_selected(C, + orient_index, + (pivot_point != V3D_AROUND_LOCAL_ORIGINS), + params->use_only_center, + gizmo_3d_tbounds_calc_fn, + tbounds, + nullptr, + rv3d ? &rv3d->twdrawflag : nullptr); + + if (totsel) { + mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* centroid! */ + + bGPdata *gpd = CTX_data_gpencil_data(C); + const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); + if (!is_gp_edit && (obedit || (ob && (ob->mode & (OB_MODE_POSE | OB_MODE_SCULPT))))) { + if (ob && (ob->mode & OB_MODE_POSE)) { + invert_m4_m4(ob->world_to_object, ob->object_to_world); + } + mul_m4_v3(ob->object_to_world, tbounds->center); + mul_m4_v3(ob->object_to_world, tbounds->min); + mul_m4_v3(ob->object_to_world, tbounds->max); + } + } + + if (rv3d) { + if (totsel == 0) { + unit_m4(rv3d->twmat); + unit_m3(rv3d->tw_axis_matrix); + zero_v3(rv3d->tw_axis_min); + zero_v3(rv3d->tw_axis_max); + } + else { + copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis); + copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min); + copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max); + } } return totsel; @@ -999,46 +1038,89 @@ static void gizmo_get_idot(const RegionView3D *rv3d, float r_idot[3]) } } -void gizmo_prepare_mat(const bContext *C, RegionView3D *rv3d, const TransformBounds *tbounds) +static bool gizmo_3d_calc_pos(const bContext *C, + const Scene *scene, + const TransformBounds *tbounds, + const short pivot_type, + float r_pivot_pos[3]) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + zero_v3(r_pivot_pos); - switch (scene->toolsettings->transform_pivot_point) { - case V3D_AROUND_CENTER_BOUNDS: + switch (pivot_type) { + case V3D_AROUND_CURSOR: + copy_v3_v3(r_pivot_pos, scene->cursor.location); + return true; case V3D_AROUND_ACTIVE: { - mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); - - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { - BKE_view_layer_synced_ensure(scene, view_layer); - Object *ob = BKE_view_layer_active_object_get(view_layer); - if (ob != nullptr) { - /* Grease Pencil uses object origin. */ - bGPdata *gpd = CTX_data_gpencil_data(C); - if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - ED_object_calc_active_center(ob, false, rv3d->twmat[3]); - } - else { - 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]); - } - } + ViewLayer *view_layer = CTX_data_view_layer(C); + BKE_view_layer_synced_ensure(scene, view_layer); + Object *ob = BKE_view_layer_active_object_get(view_layer); + if (ob != nullptr) { + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { + SculptSession *ss = ob->sculpt; + copy_v3_v3(r_pivot_pos, ss->pivot_pos); + return true; } + else if (ED_object_calc_active_center(ob, false, r_pivot_pos)) { + return true; + } + } + } + [[fallthrough]]; + case V3D_AROUND_CENTER_BOUNDS: { + TransformBounds tbounds_stack; + if (tbounds == nullptr) { + TransformCalcParams calc_params{}; + calc_params.use_only_center = true; + if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds_stack, nullptr)) { + tbounds = &tbounds_stack; + } + } + if (tbounds) { + mid_v3_v3v3(r_pivot_pos, tbounds->min, tbounds->max); + return true; } 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; + case V3D_AROUND_CENTER_MEDIAN: { + if (tbounds) { + copy_v3_v3(r_pivot_pos, tbounds->center); + return true; + } + + const auto gizmo_3d_calc_center_fn = [](const float co[3], void *data) { + float *center = static_cast(data); + add_v3_v3(center, co); + }; + const float(*r_mat)[4] = nullptr; + int totsel; + totsel = gizmo_3d_foreach_selected(C, + 0, + (pivot_type != V3D_AROUND_LOCAL_ORIGINS), + true, + gizmo_3d_calc_center_fn, + r_pivot_pos, + &r_mat, + nullptr); + if (totsel) { + mul_v3_fl(r_pivot_pos, 1.0f / float(totsel)); + if (r_mat) { + mul_m4_v3(r_mat, r_pivot_pos); + } + return true; + } + } } + + return false; +} + +void gizmo_prepare_mat(const struct bContext *C, + struct RegionView3D *rv3d, + const struct TransformBounds *tbounds) +{ + Scene *scene = CTX_data_scene(C); + gizmo_3d_calc_pos(C, scene, tbounds, scene->toolsettings->transform_pivot_point, rv3d->twmat[3]); } /** @@ -1598,7 +1680,7 @@ static int gizmo_modal(bContext *C, TransformCalcParams calc_params{}; calc_params.use_only_center = true; - if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds)) { + if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds, rv3d)) { gizmo_prepare_mat(C, rv3d, &tbounds); for (wmGizmo *gz = static_cast(gzgroup->gizmos.first); gz; gz = gz->next) { WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]); @@ -1875,11 +1957,12 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) TransformCalcParams calc_params{}; calc_params.use_only_center = true; calc_params.orientation_index = orient_index + 1; - if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0))) { + if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds, rv3d) == 0))) { return; } - gizmo_prepare_mat(C, rv3d, &tbounds); + gizmo_3d_calc_pos( + C, scene, &tbounds, scene->toolsettings->transform_pivot_point, rv3d->twmat[3]); gizmogroup_refresh_from_matrix(gzgroup, rv3d->twmat, nullptr, false); } @@ -2378,3 +2461,11 @@ void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t) } MAN_ITER_AXES_END; } + +bool ED_transform_calc_pivot_pos(const struct bContext *C, + const short pivot_type, + float r_pivot_pos[3]) +{ + Scene *scene = CTX_data_scene(C); + return gizmo_3d_calc_pos(C, scene, nullptr, pivot_type, r_pivot_pos); +} diff --git a/source/blender/editors/transform/transform_gizmo_3d_cage.cc b/source/blender/editors/transform/transform_gizmo_3d_cage.cc index 30fc53e1e78..67e7fcfb922 100644 --- a/source/blender/editors/transform/transform_gizmo_3d_cage.cc +++ b/source/blender/editors/transform/transform_gizmo_3d_cage.cc @@ -111,7 +111,7 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr TransformCalcParams calc_params{}; calc_params.use_local_axis = true; calc_params.orientation_index = orient_index + 1; - if ((ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) || + if ((ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds, rv3d) == 0) || equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) { WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); } diff --git a/source/blender/editors/transform/transform_gizmo_3d_shear.cc b/source/blender/editors/transform/transform_gizmo_3d_shear.cc index c763ec93ccc..4e3e9ede92b 100644 --- a/source/blender/editors/transform/transform_gizmo_3d_shear.cc +++ b/source/blender/editors/transform/transform_gizmo_3d_shear.cc @@ -120,7 +120,7 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg TransformCalcParams calc_params{}; calc_params.use_local_axis = false; calc_params.orientation_index = orient_index + 1; - if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds) == 0) { + if (ED_transform_calc_gizmo_stats(C, &calc_params, &tbounds, rv3d) == 0) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { wmGizmo *gz = xgzgroup->gizmo[i][j]; diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index 01270df5f14..a622ea365d3 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -233,6 +233,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) } Scene *scene = CTX_data_scene(C); + RegionView3D *rv3d = CTX_wm_region_data(C); int axis_type; { @@ -255,7 +256,8 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) &(struct TransformCalcParams){ .orientation_index = V3D_ORIENT_NORMAL + 1, }, - &tbounds_normal)) { + &tbounds_normal, + rv3d)) { unit_m3(tbounds_normal.axis); } copy_m3_m3(ggd->data.normal_mat3, tbounds_normal.axis); @@ -266,7 +268,8 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) &(struct TransformCalcParams){ .orientation_index = ggd->data.orientation_index + 1, }, - &tbounds)) { + &tbounds, + rv3d)) { return; }