diff options
author | Antonis Ryakiotakis <kalast@gmail.com> | 2022-02-07 21:37:15 +0300 |
---|---|---|
committer | Antonis Ryakiotakis <kalast@gmail.com> | 2022-02-07 21:37:15 +0300 |
commit | d8c05502272990173381bfd2590884bbc95aa5f5 (patch) | |
tree | 8bd65efacbe6484b838d4550597d0f4a54ddddd9 /source/blender/editors/space_view3d/view3d_navigate_dolly.c | |
parent | b64d551f3b2fa409b4eeefb641fc581eb6cd0bd6 (diff) | |
parent | fe1816f67fbc6aaf383ec77847d668367335d093 (diff) |
Merge branch 'master' into KTX_supportKTX_support
Diffstat (limited to 'source/blender/editors/space_view3d/view3d_navigate_dolly.c')
-rw-r--r-- | source/blender/editors/space_view3d/view3d_navigate_dolly.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/source/blender/editors/space_view3d/view3d_navigate_dolly.c b/source/blender/editors/space_view3d/view3d_navigate_dolly.c new file mode 100644 index 00000000000..02783c2a244 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_navigate_dolly.c @@ -0,0 +1,337 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spview3d + */ + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" + +#include "RNA_access.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" +#include "view3d_navigate.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Dolly Operator + * + * Like zoom but translates the view offset along the view direction + * which avoids #RegionView3D.dist approaching zero. + * \{ */ + +/* This is an exact copy of #viewzoom_modal_keymap. */ +void viewdolly_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); +} + +static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (ED_view3d_offset_lock_check(v3d, rv3d)) { + BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked"); + return true; + } + return false; +} + +static void view_dolly_to_vector_3d(ARegion *region, + const float orig_ofs[3], + const float dvec[3], + float dfac) +{ + RegionView3D *rv3d = region->regiondata; + madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); +} + +static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const bool zoom_invert) +{ + float zfac = 1.0; + + { + float len1, len2; + + if (U.uiflag & USER_ZOOM_HORIZ) { + len1 = (vod->region->winrct.xmax - xy[0]) + 5; + len2 = (vod->region->winrct.xmax - vod->init.event_xy[0]) + 5; + } + else { + len1 = (vod->region->winrct.ymax - xy[1]) + 5; + len2 = (vod->region->winrct.ymax - vod->init.event_xy[1]) + 5; + } + if (zoom_invert) { + SWAP(float, len1, len2); + } + + zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); + } + + if (zfac != 1.0f) { + view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac); + } + + if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(vod->area, vod->region); + } + + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->region); +} + +static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + bool use_autokey = false; + int ret = OPERATOR_RUNNING_MODAL; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewdolly_apply(vod, event->xy, (U.uiflag & USER_ZOOM_INVERT) != 0); + if (ED_screen_animation_playing(CTX_wm_manager(C))) { + use_autokey = true; + } + } + else if (event_code == VIEW_CONFIRM) { + use_autokey = true; + ret = OPERATOR_FINISHED; + } + + if (use_autokey) { + ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); + } + + if (ret & OPERATOR_FINISHED) { + viewops_data_free(C, vod); + op->customdata = NULL; + } + + return ret; +} + +static int viewdolly_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + RegionView3D *rv3d; + ScrArea *area; + ARegion *region; + float mousevec[3]; + + const int delta = RNA_int_get(op->ptr, "delta"); + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + + area = vod->area; + region = vod->region; + copy_v3_v3(mousevec, vod->init.mousevec); + } + else { + area = CTX_wm_area(C); + region = CTX_wm_region(C); + negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]); + normalize_v3(mousevec); + } + + v3d = area->spacedata.first; + rv3d = region->regiondata; + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + /* overwrite the mouse vector with the view direction (zoom into the center) */ + if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + normalize_v3_v3(mousevec, rv3d->viewinv[2]); + negate_v3(mousevec); + } + + view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 1.8f : 0.2f); + + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_sync(area, region); + } + + ED_view3d_camera_lock_sync(CTX_data_ensure_evaluated_depsgraph(C), v3d, rv3d); + + ED_region_tag_redraw(region); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +/* copied from viewzoom_invoke(), changes here may apply there */ +static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + if (viewdolly_offset_lock_check(C, op)) { + return OPERATOR_CANCELLED; + } + + const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); + + vod = op->customdata = viewops_data_create( + C, + event, + (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) | + (use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); + + ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region); + + /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */ + /* switch from camera view when: */ + if (vod->rv3d->persp != RV3D_PERSP) { + if (vod->rv3d->persp == RV3D_CAMOB) { + /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ + const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP); + } + else { + vod->rv3d->persp = RV3D_PERSP; + } + ED_region_tag_redraw(vod->region); + } + + /* if one or the other zoom position aren't set, set from event */ + if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { + RNA_int_set(op->ptr, "mx", event->xy[0]); + RNA_int_set(op->ptr, "my", event->xy[1]); + } + + if (RNA_struct_property_is_set(op->ptr, "delta")) { + viewdolly_exec(C, op); + } + else { + /* overwrite the mouse vector with the view direction (zoom into the center) */ + if ((use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + normalize_v3(vod->init.mousevec); + } + + if (event->type == MOUSEZOOM) { + /* Bypass Zoom invert flag for track pads (pass false always) */ + + if (U.uiflag & USER_ZOOM_HORIZ) { + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0]; + } + else { + /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] - + event->prev_xy[0]; + } + viewdolly_apply(vod, event->prev_xy, (U.uiflag & USER_ZOOM_INVERT) == 0); + + viewops_data_free(C, op->customdata); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_FINISHED; +} + +static void viewdolly_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op->customdata); + op->customdata = NULL; +} + +void VIEW3D_OT_dolly(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dolly View"; + ot->description = "Dolly in/out in the view"; + ot->idname = "VIEW3D_OT_dolly"; + + /* api callbacks */ + ot->invoke = viewdolly_invoke; + ot->exec = viewdolly_exec; + ot->modal = viewdolly_modal; + ot->poll = view3d_rotation_poll; + ot->cancel = viewdolly_cancel; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; + + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); +} + +/** \} */ |