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; }