Cleanup: split 'transform_gizmo_3d.cc' in more specific units

Split `transform_gizmo_3d.cc` in:
- `transform_gizmo_3d.cc`
- `transform_gizmo_3d_cage.cc`
- `transform_gizmo_3d_shear.cc`

Split `transform.h` in:
- `transform.h`
- `transform_gizmo.h`

Also:
- Move functions `gimbal_axis_pose` and `gimbal_axis_object` to
`transform_orentations.c` (they are not used in `transform_gizmo_3d.cc`)

Pull Request #105256
This commit is contained in:
Germano Cavalcante 2023-02-28 14:12:14 +01:00 committed by Germano Cavalcante
parent 5edca02d08
commit 3c94e2ab4c
14 changed files with 682 additions and 596 deletions

View File

@ -55,6 +55,8 @@ set(SRC
transform_generics.c
transform_gizmo_2d.c
transform_gizmo_3d.cc
transform_gizmo_3d_cage.cc
transform_gizmo_3d_shear.cc
transform_gizmo_extrude_3d.c
transform_input.c
transform_mode.c
@ -99,6 +101,7 @@ set(SRC
transform_convert.h
transform_data.h
transform_draw_cursors.h
transform_gizmo.h
transform_mode.h
transform_orientations.h
transform_snap.h

View File

@ -52,6 +52,7 @@
#include "transform_constraints.h"
#include "transform_convert.h"
#include "transform_draw_cursors.h"
#include "transform_gizmo.h"
#include "transform_mode.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -728,40 +728,6 @@ void transform_final_value_get(const TransInfo *t, float *value, int value_num);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Gizmo
* \{ */
/* transform_gizmo.c */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
/**
* Set the #T_NO_GIZMO flag.
*
* \note This maintains the conventional behavior of not displaying the gizmo if the operator has
* been triggered by shortcuts.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t);
/**
* Change the gizmo and its orientation to match the transform state.
*
* \note This used while the modal operator is running so changes to the constraint or mode show
* the gizmo associated with that state, as if it had been the initial gizmo dragged.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t);
/**
* Restores the non-modal state of the gizmo.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t);
/** \} */
/* -------------------------------------------------------------------- */
/** \name TransData Creation and General Handling
* \{ */

View File

@ -34,6 +34,7 @@
#include "UI_resources.h"
#include "transform.h"
#include "transform_gizmo.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -35,6 +35,7 @@
#include "RNA_prototypes.h"
#include "transform.h"
#include "transform_orientations.h"
#include "transform_snap.h"
/* Own include. */

View File

@ -49,6 +49,7 @@
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_mode.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup edtransform
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Types/
* \{ */
struct ARegion;
struct bContext;
struct bScreen;
struct RegionView3D;
struct Scene;
struct ScrArea;
struct TransformBounds;
struct TransInfo;
struct wmGizmoGroup;
struct wmGizmoGroupType;
struct wmMsgBus;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Gizmo
* \{ */
/* transform_gizmo_3d.c */
#define GIZMO_AXIS_LINE_WIDTH 2.0f
void gizmo_prepare_mat(const struct bContext *C,
struct RegionView3D *rv3d,
const struct TransformBounds *tbounds);
void gizmo_xform_message_subscribe(struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
struct Scene *scene,
struct bScreen *screen,
struct ScrArea *area,
struct ARegion *region,
void (*type_fn)(struct wmGizmoGroupType *));
/**
* Set the #T_NO_GIZMO flag.
*
* \note This maintains the conventional behavior of not displaying the gizmo if the operator has
* been triggered by shortcuts.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t);
/**
* Change the gizmo and its orientation to match the transform state.
*
* \note This used while the modal operator is running so changes to the constraint or mode show
* the gizmo associated with that state, as if it had been the initial gizmo dragged.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t);
/**
* Restores the non-modal state of the gizmo.
*/
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t);
/** \} */
#ifdef __cplusplus
}
#endif

View File

@ -42,7 +42,8 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "transform.h" /* own include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Shared Callback's

View File

@ -8,31 +8,15 @@
* Used for 3D View
*/
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_crazyspace.hh"
#include "BKE_curve.h"
#include "BKE_curves.hh"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@ -41,12 +25,10 @@
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#include "BLI_array_utils.h"
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
#include "ED_armature.h"
#include "ED_curves.h"
@ -56,9 +38,7 @@
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
@ -67,12 +47,9 @@
/* local module include */
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_snap.h"
#include "MEM_guardedalloc.h"
#include "GPU_state.h"
static wmGizmoGroupType *g_GGT_xform_gizmo = nullptr;
static wmGizmoGroupType *g_GGT_xform_gizmo_context = nullptr;
@ -527,101 +504,6 @@ static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *e
}
}
/* 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;
}
bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3])
{
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->object_to_world);
mul_m3_m3m3(gmat, obmat, mat);
}
else {
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, tmat);
}
normalize_m3(gmat);
return true;
}
bool gimbal_axis_object(Object *ob, float gmat[3][3])
{
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->object_to_world);
normalize_m3(parent_mat);
mul_m3_m3m3(gmat, parent_mat, gmat);
}
return 1;
}
int ED_transform_calc_gizmo_stats(const bContext *C,
const TransformCalcParams *params,
TransformBounds *tbounds)
@ -1117,9 +999,7 @@ static void gizmo_get_idot(const RegionView3D *rv3d, float r_idot[3])
}
}
static void gizmo_prepare_mat(const bContext *C,
RegionView3D *rv3d,
const TransformBounds *tbounds)
void gizmo_prepare_mat(const bContext *C, RegionView3D *rv3d, const TransformBounds *tbounds)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@ -1197,13 +1077,13 @@ static void gizmo_line_range(const int twtype, const short axis_type, float *r_s
}
}
static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
ScrArea *area,
ARegion *region,
void (*type_fn)(wmGizmoGroupType *))
void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
ScrArea *area,
ARegion *region,
void (*type_fn)(wmGizmoGroupType *))
{
/* Subscribe to view properties */
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh{};
@ -2337,437 +2217,6 @@ void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Scale Cage Gizmo
* \{ */
struct XFormCageWidgetGroup {
wmGizmo *gizmo;
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_cage_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(
MEM_mallocN(sizeof(XFormCageWidgetGroup), __func__));
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
xgzgroup->gizmo = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
wmGizmo *gz = xgzgroup->gizmo;
RNA_enum_set(
gz->ptr, "transform", ED_GIZMO_CAGE_XFORM_FLAG_SCALE | ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE);
gz->color[0] = 1;
gz->color_hi[0] = 1;
gzgroup->customdata = xgzgroup;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
PointerRNA *ptr;
/* assign operator */
PropertyRNA *prop_release_confirm = nullptr;
PropertyRNA *prop_constraint_axis = nullptr;
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
for (int z = 0; z < 3; z++) {
const bool constraint[3] = {x != 1, y != 1, z != 1};
ptr = WM_gizmo_operator_set(gz, i, ot_resize, nullptr);
if (prop_release_confirm == nullptr) {
prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
}
RNA_property_boolean_set(ptr, prop_release_confirm, true);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
i++;
}
}
}
}
}
static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
Scene *scene = CTX_data_scene(C);
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
wmGizmo *gz = xgzgroup->gizmo;
TransformBounds tbounds;
const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE);
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) ||
equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) {
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
if (tbounds.use_matrix_space) {
copy_m4_m4(gz->matrix_space, tbounds.matrix_space);
}
else {
unit_m4(gz->matrix_space);
}
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
float dims[3];
sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
RNA_float_set_array(gz->ptr, "dimensions", dims);
mul_v3_fl(dims, 0.5f);
copy_m4_m3(gz->matrix_offset, rv3d->tw_axis_matrix);
mid_v3_v3v3(gz->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
mul_m3_v3(rv3d->tw_axis_matrix, gz->matrix_offset[3]);
float matrix_offset_global[4][4];
mul_m4_m4m4(matrix_offset_global, gz->matrix_space, gz->matrix_offset);
PropertyRNA *prop_center_override = nullptr;
float center[3];
float center_global[3];
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
center[0] = float(1 - x) * dims[0];
for (int y = 0; y < 3; y++) {
center[1] = float(1 - y) * dims[1];
for (int z = 0; z < 3; z++) {
center[2] = float(1 - z) * dims[2];
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, i);
if (prop_center_override == nullptr) {
prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
}
mul_v3_m4v3(center_global, matrix_offset_global, center);
RNA_property_float_set_array(&gzop->ptr, prop_center_override, center_global);
i++;
}
}
}
}
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
}
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_cage_refresh(C, gzgroup);
}
break;
}
}
}
}
void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_cage_poll;
gzgt->setup = WIDGETGROUP_xform_cage_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_cage_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform Shear Gizmo
* \{ */
struct XFormShearWidgetGroup {
wmGizmo *gizmo[3][2];
/** View aligned gizmos. */
wmGizmo *gizmo_view[4];
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_shear_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_shear_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(
MEM_mallocN(sizeof(XFormShearWidgetGroup), __func__));
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
wmOperatorType *ot_shear = WM_operatortype_find("TRANSFORM_OT_shear", true);
float axis_color[3][3];
for (int i = 0; i < 3; i++) {
UI_GetThemeColor3fv(TH_AXIS_X + i, axis_color[i]);
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(gz->ptr, "draw_options", 0); /* No stem. */
copy_v3_fl(gz->color, 1.0f);
gz->color[3] = 0.5f;
WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo_view[i] = gz;
/* Unlike the other gizmos, this never changes so can be set on setup. */
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
RNA_enum_set(&gzop->ptr, "orient_type", V3D_ORIENT_VIEW);
RNA_enum_set(&gzop->ptr, "orient_axis", 2);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", ((i % 2) ? 0 : 1));
}
gzgroup->customdata = xgzgroup;
}
static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
TransformBounds tbounds;
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag(
scene, SCE_ORIENT_ROTATE);
const int orient_index = BKE_scene_orientation_slot_get_index(orient_slot);
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) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
else {
gizmo_prepare_mat(C, rv3d, &tbounds);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
WM_gizmo_set_matrix_rotation_from_yz_axis(gz, rv3d->twmat[i_ortho_a], rv3d->twmat[i]);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
RNA_float_set_array(&gzop->ptr, "orient_matrix", &tbounds.axis[0][0]);
RNA_enum_set(&gzop->ptr, "orient_type", orient_slot->type);
RNA_enum_set(&gzop->ptr, "orient_axis", i_ortho_b);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", i_ortho_a);
mul_v3_fl(gz->matrix_basis[0], 0.5f);
mul_v3_fl(gz->matrix_basis[1], 6.0f);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(
gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
/* Shear is like rotate, use the rotate setting. */
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(
scene, SCE_ORIENT_ROTATE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_shear_refresh(C, gzgroup);
}
break;
}
}
}
for (int i = 0; i < 4; i++) {
const float outer_thin = 0.3f;
const float outer_offset = 1.0f / 0.3f;
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_matrix_rotation_from_yz_axis(
gz, rv3d->viewinv[(i + 1) % 2], rv3d->viewinv[i % 2]);
if (i >= 2) {
negate_v3(gz->matrix_basis[1]);
negate_v3(gz->matrix_basis[2]);
}
/* No need for depth with view aligned gizmos. */
mul_v3_fl(gz->matrix_basis[0], 0.0f);
mul_v3_fl(gz->matrix_basis[1], 20.0f + ((1.0f / outer_thin) * 1.8f));
mul_v3_fl(gz->matrix_basis[2], outer_thin);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
gz->matrix_offset[3][2] = outer_offset;
}
/* Basic ordering for drawing only. */
{
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
/* Since we have two pairs of each axis,
* bias the values so gizmos that are orthogonal to the view get priority.
* This means we never default to shearing along
* the view axis in the case of an overlap. */
float axis_order[3], axis_bias[3];
copy_v3_v3(axis_order, gz->matrix_basis[2]);
copy_v3_v3(axis_bias, gz->matrix_basis[1]);
if (dot_v3v3(axis_bias, rv3d->viewinv[2]) < 0.0f) {
negate_v3(axis_bias);
}
madd_v3_v3fl(axis_order, axis_bias, 0.01f);
gz->temp.f = dot_v3v3(rv3d->viewinv[2], axis_order);
}
BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
}
}
void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_shear_poll;
gzgt->setup = WIDGETGROUP_xform_shear_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_shear_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_shear_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_shear_draw_prepare;
}
/** \} */
static wmGizmoGroup *gizmogroup_xform_find(TransInfo *t)
{
wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->gizmo_map);

View File

@ -0,0 +1,223 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*
* \name 3D Transform Gizmo
*
* Used for 3D View
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_scene.h"
#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "RNA_access.h"
/* local module include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Scale Cage Gizmo
* \{ */
struct XFormCageWidgetGroup {
wmGizmo *gizmo;
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_cage_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(
MEM_mallocN(sizeof(XFormCageWidgetGroup), __func__));
const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
xgzgroup->gizmo = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
wmGizmo *gz = xgzgroup->gizmo;
RNA_enum_set(
gz->ptr, "transform", ED_GIZMO_CAGE_XFORM_FLAG_SCALE | ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE);
gz->color[0] = 1;
gz->color_hi[0] = 1;
gzgroup->customdata = xgzgroup;
{
wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
PointerRNA *ptr;
/* assign operator */
PropertyRNA *prop_release_confirm = nullptr;
PropertyRNA *prop_constraint_axis = nullptr;
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
for (int z = 0; z < 3; z++) {
const bool constraint[3] = {x != 1, y != 1, z != 1};
ptr = WM_gizmo_operator_set(gz, i, ot_resize, nullptr);
if (prop_release_confirm == nullptr) {
prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
}
RNA_property_boolean_set(ptr, prop_release_confirm, true);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
i++;
}
}
}
}
}
static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
Scene *scene = CTX_data_scene(C);
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
wmGizmo *gz = xgzgroup->gizmo;
TransformBounds tbounds;
const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, SCE_ORIENT_SCALE);
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) ||
equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) {
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
if (tbounds.use_matrix_space) {
copy_m4_m4(gz->matrix_space, tbounds.matrix_space);
}
else {
unit_m4(gz->matrix_space);
}
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
float dims[3];
sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
RNA_float_set_array(gz->ptr, "dimensions", dims);
mul_v3_fl(dims, 0.5f);
copy_m4_m3(gz->matrix_offset, rv3d->tw_axis_matrix);
mid_v3_v3v3(gz->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
mul_m3_v3(rv3d->tw_axis_matrix, gz->matrix_offset[3]);
float matrix_offset_global[4][4];
mul_m4_m4m4(matrix_offset_global, gz->matrix_space, gz->matrix_offset);
PropertyRNA *prop_center_override = nullptr;
float center[3];
float center_global[3];
int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
for (int x = 0; x < 3; x++) {
center[0] = float(1 - x) * dims[0];
for (int y = 0; y < 3; y++) {
center[1] = float(1 - y) * dims[1];
for (int z = 0; z < 3; z++) {
center[2] = float(1 - z) * dims[2];
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, i);
if (prop_center_override == nullptr) {
prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
}
mul_v3_m4v3(center_global, matrix_offset_global, center);
RNA_property_float_set_array(&gzop->ptr, prop_center_override, center_global);
i++;
}
}
}
}
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
}
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormCageWidgetGroup *xgzgroup = static_cast<XFormCageWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_cage_refresh(C, gzgroup);
}
break;
}
}
}
}
void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_cage_poll;
gzgt->setup = WIDGETGROUP_xform_cage_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_cage_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
}
/** \} */

View File

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*
* \name 3D Transform Gizmo
*
* Used for 3D View
*/
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_scene.h"
#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "UI_resources.h"
#include "RNA_access.h"
/* local module include */
#include "transform.h"
#include "transform_gizmo.h"
/* -------------------------------------------------------------------- */
/** \name Transform Shear Gizmo
* \{ */
struct XFormShearWidgetGroup {
wmGizmo *gizmo[3][2];
/** View aligned gizmos. */
wmGizmo *gizmo_view[4];
/* Only for view orientation. */
struct {
float viewinv_m3[3][3];
} prev;
};
static bool WIDGETGROUP_xform_shear_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
View3D *v3d = CTX_wm_view3d(C);
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
return false;
}
return true;
}
static void WIDGETGROUP_xform_shear_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(
MEM_mallocN(sizeof(XFormShearWidgetGroup), __func__));
const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
wmOperatorType *ot_shear = WM_operatortype_find("TRANSFORM_OT_shear", true);
float axis_color[3][3];
for (int i = 0; i < 3; i++) {
UI_GetThemeColor3fv(TH_AXIS_X + i, axis_color[i]);
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
gz->color[3] = 0.5f;
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo[i][j] = gz;
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
RNA_enum_set(gz->ptr, "draw_options", 0); /* No stem. */
copy_v3_fl(gz->color, 1.0f);
gz->color[3] = 0.5f;
WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, nullptr);
RNA_boolean_set(ptr, "release_confirm", 1);
xgzgroup->gizmo_view[i] = gz;
/* Unlike the other gizmos, this never changes so can be set on setup. */
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
RNA_enum_set(&gzop->ptr, "orient_type", V3D_ORIENT_VIEW);
RNA_enum_set(&gzop->ptr, "orient_axis", 2);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", ((i % 2) ? 0 : 1));
}
gzgroup->customdata = xgzgroup;
}
static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
TransformBounds tbounds;
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get_from_flag(
scene, SCE_ORIENT_ROTATE);
const int orient_index = BKE_scene_orientation_slot_get_index(orient_slot);
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) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
}
else {
gizmo_prepare_mat(C, rv3d, &tbounds);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
wmGizmo *gz = xgzgroup->gizmo[i][j];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
const int i_ortho_a = (i + j + 1) % 3;
const int i_ortho_b = (i + (1 - j) + 1) % 3;
WM_gizmo_set_matrix_rotation_from_yz_axis(gz, rv3d->twmat[i_ortho_a], rv3d->twmat[i]);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
RNA_float_set_array(&gzop->ptr, "orient_matrix", &tbounds.axis[0][0]);
RNA_enum_set(&gzop->ptr, "orient_type", orient_slot->type);
RNA_enum_set(&gzop->ptr, "orient_axis", i_ortho_b);
RNA_enum_set(&gzop->ptr, "orient_axis_ortho", i_ortho_a);
mul_v3_fl(gz->matrix_basis[0], 0.5f);
mul_v3_fl(gz->matrix_basis[1], 6.0f);
}
}
for (int i = 0; i < 4; i++) {
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
wmMsgBus *mbus)
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
gizmo_xform_message_subscribe(
gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
XFormShearWidgetGroup *xgzgroup = static_cast<XFormShearWidgetGroup *>(gzgroup->customdata);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
Scene *scene = CTX_data_scene(C);
/* Shear is like rotate, use the rotate setting. */
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(
scene, SCE_ORIENT_ROTATE);
switch (orient_slot->type) {
case V3D_ORIENT_VIEW: {
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
/* Take care calling refresh from draw_prepare,
* this should be OK because it's only adjusting the cage orientation. */
WIDGETGROUP_xform_shear_refresh(C, gzgroup);
}
break;
}
}
}
for (int i = 0; i < 4; i++) {
const float outer_thin = 0.3f;
const float outer_offset = 1.0f / 0.3f;
wmGizmo *gz = xgzgroup->gizmo_view[i];
WM_gizmo_set_matrix_rotation_from_yz_axis(
gz, rv3d->viewinv[(i + 1) % 2], rv3d->viewinv[i % 2]);
if (i >= 2) {
negate_v3(gz->matrix_basis[1]);
negate_v3(gz->matrix_basis[2]);
}
/* No need for depth with view aligned gizmos. */
mul_v3_fl(gz->matrix_basis[0], 0.0f);
mul_v3_fl(gz->matrix_basis[1], 20.0f + ((1.0f / outer_thin) * 1.8f));
mul_v3_fl(gz->matrix_basis[2], outer_thin);
WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
gz->matrix_offset[3][2] = outer_offset;
}
/* Basic ordering for drawing only. */
{
LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
/* Since we have two pairs of each axis,
* bias the values so gizmos that are orthogonal to the view get priority.
* This means we never default to shearing along
* the view axis in the case of an overlap. */
float axis_order[3], axis_bias[3];
copy_v3_v3(axis_order, gz->matrix_basis[2]);
copy_v3_v3(axis_bias, gz->matrix_basis[1]);
if (dot_v3v3(axis_bias, rv3d->viewinv[2]) < 0.0f) {
negate_v3(axis_bias);
}
madd_v3_v3fl(axis_order, axis_bias, 0.01f);
gz->temp.f = dot_v3v3(rv3d->viewinv[2], axis_order);
}
BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
}
}
void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
{
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = WIDGETGROUP_xform_shear_poll;
gzgt->setup = WIDGETGROUP_xform_shear_setup;
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = WIDGETGROUP_xform_shear_refresh;
gzgt->message_subscribe = WIDGETGROUP_xform_shear_message_subscribe;
gzgt->draw_prepare = WIDGETGROUP_xform_shear_draw_prepare;
}
/** \} */

View File

@ -29,6 +29,7 @@
#include "transform.h"
#include "transform_convert.h"
#include "transform_gizmo.h"
#include "transform_orientations.h"
#include "transform_snap.h"

View File

@ -230,6 +230,101 @@ static TransformOrientation *createMeshSpace(bContext *C,
return addMatrixSpace(C, mat, name, overwrite);
}
static bool test_rotmode_euler(short rotmode)
{
return ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT) ? 0 : 1;
}
/* 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);
}
bool gimbal_axis_pose(Object *ob, const bPoseChannel *pchan, float gmat[3][3])
{
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->object_to_world);
mul_m3_m3m3(gmat, obmat, mat);
}
else {
/* needed if object transformation isn't identity */
copy_m3_m4(obmat, ob->object_to_world);
mul_m3_m3m3(gmat, obmat, tmat);
}
normalize_m3(gmat);
return true;
}
bool gimbal_axis_object(Object *ob, float gmat[3][3])
{
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->object_to_world);
normalize_m3(parent_mat);
mul_m3_m3m3(gmat, parent_mat, gmat);
}
return 1;
}
bool transform_orientations_create_from_axis(float mat[3][3],
const float x[3],
const float y[3],

View File

@ -9,8 +9,13 @@
#include "RE_engine.h"
struct bPoseChannel;
struct Object;
struct TransInfo;
bool gimbal_axis_pose(struct Object *ob, const struct bPoseChannel *pchan, float gmat[3][3]);
bool gimbal_axis_object(struct Object *ob, float gmat[3][3]);
/**
* Sets the matrix of the specified space orientation.
* If the matrix cannot be obtained, an orientation different from the one informed is returned.