tornavis/source/blender/editors/transform/transform_mode_snapsource.cc

264 lines
7.3 KiB
C++

/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*/
#include "MEM_guardedalloc.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.hh"
#include "ED_screen.hh"
#include "ED_transform_snap_object_context.hh"
#include "transform.hh"
#include "transform_convert.hh"
#include "transform_gizmo.hh"
#include "transform_snap.hh"
#include "transform_mode.hh"
#define RESET_TRANSFORMATION
#define REMOVE_GIZMO
using namespace blender;
/* -------------------------------------------------------------------- */
/** \name Transform Element
* \{ */
/**
* \note Small arrays / data-structures should be stored copied for faster memory access.
*/
struct SnapSouceCustomData {
TransModeInfo *mode_info_prev;
void *customdata_mode_prev;
eSnapTargetOP target_operation_prev;
eSnapMode snap_mode_confirm;
struct {
void (*apply)(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]);
void (*post)(TransInfo *t, float values[3]);
bool use_virtual_mval;
} mouse_prev;
};
static void snapsource_end(TransInfo *t)
{
t->modifiers &= ~MOD_EDIT_SNAP_SOURCE;
/* Restore. */
SnapSouceCustomData *customdata = static_cast<SnapSouceCustomData *>(t->custom.mode.data);
t->mode_info = customdata->mode_info_prev;
t->custom.mode.data = customdata->customdata_mode_prev;
t->tsnap.target_operation = customdata->target_operation_prev;
t->mouse.apply = customdata->mouse_prev.apply;
t->mouse.post = customdata->mouse_prev.post;
t->mouse.use_virtual_mval = customdata->mouse_prev.use_virtual_mval;
MEM_freeN(customdata);
transform_gizmo_3d_model_from_constraint_and_mode_set(t);
tranform_snap_source_restore_context(t);
}
static void snapsource_confirm(TransInfo *t)
{
BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
getSnapPoint(t, t->tsnap.snap_source);
t->tsnap.snap_source_fn = nullptr;
t->tsnap.source_type = t->tsnap.target_type;
t->tsnap.status |= SNAP_SOURCE_FOUND;
SnapSouceCustomData *customdata = static_cast<SnapSouceCustomData *>(t->custom.mode.data);
t->tsnap.mode = customdata->snap_mode_confirm;
float2 mval;
#ifndef RESET_TRANSFORMATION
if (true) {
if (t->transform_matrix) {
float mat_inv[4][4];
unit_m4(mat_inv);
t->transform_matrix(t, mat_inv);
invert_m4(mat_inv);
mul_m4_v3(mat_inv, t->tsnap.snap_source);
}
else {
float mat_inv[3][3];
invert_m3_m3(mat_inv, t->mat);
mul_m3_v3(mat_inv, t->tsnap.snap_source);
sub_v3_v3(t->tsnap.snap_source, t->vec);
}
projectFloatView(t, t->tsnap.snap_source, mval);
}
else
#endif
{
mval = t->mval;
}
snapsource_end(t);
transform_input_reset(t, mval);
/* Remote individual snap projection since this mode does not use the new `snap_source`. */
t->tsnap.mode &= ~(SCE_SNAP_INDIVIDUAL_PROJECT | SCE_SNAP_INDIVIDUAL_NEAREST);
}
static eRedrawFlag snapsource_handle_event_fn(TransInfo *t, const wmEvent *event)
{
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TFM_MODAL_CONFIRM:
case TFM_MODAL_EDIT_SNAP_SOURCE_ON:
case TFM_MODAL_EDIT_SNAP_SOURCE_OFF:
if (t->modifiers & MOD_EDIT_SNAP_SOURCE) {
snapsource_confirm(t);
BLI_assert(t->state != TRANS_CONFIRM);
}
else {
t->modifiers |= MOD_EDIT_SNAP_SOURCE;
}
break;
case TFM_MODAL_CANCEL:
snapsource_end(t);
t->state = TRANS_CANCEL;
return TREDRAW_SOFT;
default:
break;
}
}
else if (event->val == KM_RELEASE && t->state == TRANS_CONFIRM) {
if (t->flag & T_RELEASE_CONFIRM && t->modifiers & MOD_EDIT_SNAP_SOURCE) {
snapsource_confirm(t);
t->flag &= ~T_RELEASE_CONFIRM;
t->state = TRANS_RUNNING;
}
}
return TREDRAW_NOTHING;
}
static void snapsource_transform_fn(TransInfo *t)
{
BLI_assert(t->modifiers & MOD_EDIT_SNAP_SOURCE);
t->tsnap.snap_target_fn(t, nullptr);
if (t->tsnap.status & SNAP_MULTI_POINTS) {
getSnapPoint(t, t->tsnap.snap_source);
}
t->redraw |= TREDRAW_SOFT;
}
void transform_mode_snap_source_init(TransInfo *t, wmOperator * /*op*/)
{
if (t->mode_info == &TransMode_snapsource) {
/* Already running. */
return;
}
if (t->tsnap.snap_target_fn) {
/* A `snap_target_fn` is required for the operation to work.
* `snap_target_fn` can be `nullptr` when transforming camera in camera view. */
return;
}
if (ELEM(t->mode, TFM_INIT, TFM_DUMMY)) {
/* Fallback */
transform_mode_init(t, nullptr, TFM_TRANSLATION);
}
SnapSouceCustomData *customdata = static_cast<SnapSouceCustomData *>(
MEM_callocN(sizeof(*customdata), __func__));
customdata->mode_info_prev = t->mode_info;
customdata->target_operation_prev = t->tsnap.target_operation;
customdata->mouse_prev.apply = t->mouse.apply;
customdata->mouse_prev.post = t->mouse.post;
customdata->mouse_prev.use_virtual_mval = t->mouse.use_virtual_mval;
customdata->customdata_mode_prev = t->custom.mode.data;
t->custom.mode.data = customdata;
if (!(t->modifiers & MOD_SNAP) || !transformModeUseSnap(t)) {
t->modifiers |= (MOD_SNAP | MOD_SNAP_FORCED);
}
t->mode_info = &TransMode_snapsource;
t->flag |= T_DRAW_SNAP_SOURCE;
t->tsnap.target_operation = SCE_SNAP_TARGET_ALL;
t->tsnap.status &= ~SNAP_SOURCE_FOUND;
customdata->snap_mode_confirm = t->tsnap.mode;
t->tsnap.mode &= ~(SCE_SNAP_TO_EDGE_PERPENDICULAR | SCE_SNAP_INDIVIDUAL_PROJECT |
SCE_SNAP_INDIVIDUAL_NEAREST);
if ((t->tsnap.mode & ~(SCE_SNAP_TO_INCREMENT | SCE_SNAP_TO_GRID)) == 0) {
/* Initialize snap modes for geometry. */
t->tsnap.mode &= ~(SCE_SNAP_TO_INCREMENT | SCE_SNAP_TO_GRID);
t->tsnap.mode |= SCE_SNAP_TO_GEOM & ~SCE_SNAP_TO_EDGE_PERPENDICULAR;
if (!(customdata->snap_mode_confirm & SCE_SNAP_TO_EDGE_PERPENDICULAR)) {
customdata->snap_mode_confirm = t->tsnap.mode;
}
}
if (t->data_type == &TransConvertType_Mesh) {
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context, nullptr, nullptr, nullptr, nullptr);
}
#ifdef RESET_TRANSFORMATION
/* Temporarily disable snapping.
* We don't want #SCE_SNAP_PROJECT to affect `recalc_data` for example. */
t->tsnap.flag &= ~SCE_SNAP;
restoreTransObjects(t);
/* Restore snapping status. */
transform_snap_flag_from_modifiers_set(t);
/* Reset initial values to restore gizmo position. */
applyMouseInput(t, &t->mouse, t->mouse.imval, t->values_final);
#endif
#ifdef REMOVE_GIZMO
wmGizmo *gz = WM_gizmomap_get_modal(t->region->gizmo_map);
if (gz) {
const wmEvent *event = CTX_wm_window(t->context)->eventstate;
# ifdef RESET_TRANSFORMATION
wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal;
modal_fn(t->context, gz, event, eWM_GizmoFlagTweak(0));
# endif
WM_gizmo_modal_set_while_modal(t->region->gizmo_map, t->context, nullptr, event);
}
#endif
t->mouse.apply = nullptr;
t->mouse.post = nullptr;
t->mouse.use_virtual_mval = false;
}
/** \} */
TransModeInfo TransMode_snapsource = {
/*flags*/ 0,
/*init_fn*/ transform_mode_snap_source_init,
/*transform_fn*/ snapsource_transform_fn,
/*transform_matrix_fn*/ nullptr,
/*handle_event_fn*/ snapsource_handle_event_fn,
/*snap_distance_fn*/ nullptr,
/*snap_apply_fn*/ nullptr,
/*draw_fn*/ nullptr,
};