Blender V5.0
view3d_navigate_walk.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
15
16#include "DNA_object_types.h"
17#include "DNA_scene_types.h"
18
19#include "MEM_guardedalloc.h"
20
21#include "BLI_kdopbvh.hh"
22#include "BLI_math_matrix.h"
23#include "BLI_math_rotation.h"
24#include "BLI_math_vector.h"
25#include "BLI_rect.h"
26#include "BLI_time.h" /* Smooth-view. */
27#include "BLI_utildefines.h"
28
29#include "BKE_context.hh"
30#include "BKE_lib_id.hh"
31#include "BKE_report.hh"
32#include "BKE_screen.hh"
33
34#include "BLT_translation.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_screen.hh"
40#include "ED_space_api.hh"
42#include "ED_undo.hh"
43
44#include "UI_resources.hh"
45
46#include "GPU_immediate.hh"
47
48#include "view3d_intern.hh" /* own include */
49#include "view3d_navigate.hh"
50
51#include <fmt/format.h>
52
53#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
54
55#ifdef WITH_INPUT_NDOF
56// # define NDOF_WALK_DEBUG
57/* NOTE(@ideasman42): Is this needed for NDOF? commented so redraw doesn't thrash. */
58// # define NDOF_WALK_DRAW_TOOMUCH
59#endif
60
61#define USE_TABLET_SUPPORT
62
63/* -------------------------------------------------------------------- */
66
67/* NOTE: these defines are saved in key-map files,
68 * do not change values but just add new ones. */
69enum {
101};
102
114
119
124
131
143
145{
146 static const EnumPropertyItem modal_items[] = {
147 {WALK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
148 {WALK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
149
150 {WALK_MODAL_DIR_FORWARD, "FORWARD", 0, "Forward", ""},
151 {WALK_MODAL_DIR_BACKWARD, "BACKWARD", 0, "Backward", ""},
152 {WALK_MODAL_DIR_LEFT, "LEFT", 0, "Left", ""},
153 {WALK_MODAL_DIR_RIGHT, "RIGHT", 0, "Right", ""},
154 {WALK_MODAL_DIR_UP, "UP", 0, "Up", ""},
155 {WALK_MODAL_DIR_DOWN, "DOWN", 0, "Down", ""},
156 {WALK_MODAL_DIR_LOCAL_UP, "LOCAL_UP", 0, "Local Up", ""},
157 {WALK_MODAL_DIR_LOCAL_DOWN, "LOCAL_DOWN", 0, "Local Down", ""},
158
159 {WALK_MODAL_DIR_FORWARD_STOP, "FORWARD_STOP", 0, "Stop Move Forward", ""},
160 {WALK_MODAL_DIR_BACKWARD_STOP, "BACKWARD_STOP", 0, "Stop Move Backward", ""},
161 {WALK_MODAL_DIR_LEFT_STOP, "LEFT_STOP", 0, "Stop Move Left", ""},
162 {WALK_MODAL_DIR_RIGHT_STOP, "RIGHT_STOP", 0, "Stop Move Right", ""},
163 {WALK_MODAL_DIR_UP_STOP, "UP_STOP", 0, "Stop Move Global Up", ""},
164 {WALK_MODAL_DIR_DOWN_STOP, "DOWN_STOP", 0, "Stop Move Global Down", ""},
165 {WALK_MODAL_DIR_LOCAL_UP_STOP, "LOCAL_UP_STOP", 0, "Stop Move Local Up", ""},
166 {WALK_MODAL_DIR_LOCAL_DOWN_STOP, "LOCAL_DOWN_STOP", 0, "Stop Move Local Down", ""},
167
168 {WALK_MODAL_TELEPORT, "TELEPORT", 0, "Teleport", "Move forward a few units at once"},
169
170 {WALK_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""},
171 {WALK_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
172
173 {WALK_MODAL_FAST_ENABLE, "FAST_ENABLE", 0, "Fast", "Move faster (walk or fly)"},
174 {WALK_MODAL_FAST_DISABLE, "FAST_DISABLE", 0, "Fast (Off)", "Resume regular speed"},
175
176 {WALK_MODAL_SLOW_ENABLE, "SLOW_ENABLE", 0, "Slow", "Move slower (walk or fly)"},
177 {WALK_MODAL_SLOW_DISABLE, "SLOW_DISABLE", 0, "Slow (Off)", "Resume regular speed"},
178
179 {WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
180 {WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump (Off)", "Stop pushing jump"},
181
182 {WALK_MODAL_GRAVITY_TOGGLE, "GRAVITY_TOGGLE", 0, "Toggle Gravity", "Toggle gravity effect"},
183
184 {WALK_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "Z Axis Correction", "Z axis correction"},
185
187 "INCREASE_JUMP",
188 0,
189 "Increase Jump Height",
190 "Increase jump height"},
192 "DECREASE_JUMP",
193 0,
194 "Decrease Jump Height",
195 "Decrease jump height"},
196
197 {0, nullptr, 0, nullptr, nullptr},
198 };
199
200 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Walk Modal");
201
202 /* This function is called for each space-type, only needs to add map once. */
203 if (keymap && keymap->modal_items) {
204 return;
205 }
206
207 keymap = WM_modalkeymap_ensure(keyconf, "View3D Walk Modal", modal_items);
208
209 /* Assign map to operators. */
210 WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk");
211}
212
214
215/* -------------------------------------------------------------------- */
218
229
236
237struct WalkInfo {
238 /* context stuff */
242 Depsgraph *depsgraph;
244
247
249 bool redraw;
250
260
262 int prev_mval[2];
264 int init_mval[2];
265
266 int moffset[2];
267
268#ifdef WITH_INPUT_NDOF
270 wmNDOFMotionData *ndof;
271#endif
272
273 /* Walk state. */
277 float speed;
279 float grid;
280
281 /* Compare between last state. */
284
286
288 float dvec_prev[3];
289
292
295
298
302
305
306#ifdef USE_TABLET_SUPPORT
309#endif
310
313 float gravity;
314
317
320
324
327
331
333
335};
336
338
339/* -------------------------------------------------------------------- */
342
343/* Prototypes. */
344#ifdef WITH_INPUT_NDOF
345static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm);
346#endif /* WITH_INPUT_NDOF */
347static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm);
348static float walk_calc_velocity_zero_time(const float gravity, const float velocity);
349
350static void drawWalkPixel(const bContext * /*C*/, ARegion *region, void *arg)
351{
352 /* Draws an aim/cross in the center. */
353 WalkInfo *walk = static_cast<WalkInfo *>(arg);
354
355 const float outer_length = 24.0f;
356 const float inner_length = 14.0f;
357 float xoff, yoff;
358 rctf viewborder;
359
362 walk->scene, walk->depsgraph, region, walk->v3d, walk->rv3d, false, &viewborder);
363 xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f;
364 yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f;
365 }
366 else {
367 xoff = float(walk->region->winx) / 2.0f;
368 yoff = float(walk->region->winy) / 2.0f;
369 }
370
372 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
373
375
377
379
380 /* North. */
381 immVertex2f(pos, xoff, yoff + inner_length);
382 immVertex2f(pos, xoff, yoff + outer_length);
383
384 /* East. */
385 immVertex2f(pos, xoff + inner_length, yoff);
386 immVertex2f(pos, xoff + outer_length, yoff);
387
388 /* South. */
389 immVertex2f(pos, xoff, yoff - inner_length);
390 immVertex2f(pos, xoff, yoff - outer_length);
391
392 /* West. */
393 immVertex2f(pos, xoff - inner_length, yoff);
394 immVertex2f(pos, xoff - outer_length, yoff);
395
396 immEnd();
398}
399
401
402/* -------------------------------------------------------------------- */
405
407{
408 if (mode == WALK_MODE_FREE) {
411 }
412 else { /* WALK_MODE_GRAVITY */
415 }
416}
417
422 WalkInfo *walk,
423 const float dvec[3],
424 float *r_distance)
425{
426 const float ray_normal[3] = {0, 0, -1}; /* down */
427 float ray_start[3];
428 float location_dummy[3];
429 float normal_dummy[3];
430 float dvec_tmp[3];
431
432 *r_distance = BVH_RAYCAST_DIST_MAX;
433
434 copy_v3_v3(ray_start, rv3d->viewinv[3]);
435
436 mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
437 add_v3_v3(ray_start, dvec_tmp);
438
441 /* Avoid having to convert the edit-mesh to a regular mesh. */
443
445 walk->depsgraph,
446 walk->v3d,
447 &snap_params,
448 ray_start,
449 ray_normal,
450 r_distance,
451 location_dummy,
452 normal_dummy);
453
454 /* Artificially scale the distance to the scene size. */
455 *r_distance /= walk->grid;
456 return ret;
457}
458
464static bool walk_ray_cast(RegionView3D *rv3d,
465 WalkInfo *walk,
466 float r_location[3],
467 float r_normal[3],
468 float *r_ray_distance)
469{
470 float ray_normal[3] = {0, 0, -1}; /* Forward axis. */
471 float ray_start[3];
472
473 *r_ray_distance = BVH_RAYCAST_DIST_MAX;
474
475 copy_v3_v3(ray_start, rv3d->viewinv[3]);
476
477 mul_mat3_m4_v3(rv3d->viewinv, ray_normal);
478
479 normalize_v3(ray_normal);
480
483
485 walk->depsgraph,
486 walk->v3d,
487 &snap_params,
488 ray_start,
489 ray_normal,
490 nullptr,
491 r_location,
492 r_normal);
493
494 /* Dot is positive if both rays are facing the same direction. */
495 if (dot_v3v3(ray_normal, r_normal) > 0) {
496 negate_v3(r_normal);
497 }
498
499 /* Artificially scale the distance to the scene size. */
500 *r_ray_distance /= walk->grid;
501
502 return ret;
503}
504
506static struct {
510
514} g_walk = {
515 /*base_speed*/ -1.0f,
516 /*userdef_speed*/ -1.0f,
517 /*jump_height*/ -1.0f,
518 /*userdef_jump_height*/ -1.0f,
520
521static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int mval[2])
522{
524 wmWindow *win = CTX_wm_window(C);
525
526 walk->rv3d = CTX_wm_region_view3d(C);
527 walk->v3d = CTX_wm_view3d(C);
528 walk->region = CTX_wm_region(C);
530 walk->scene = CTX_data_scene(C);
531
532#ifdef NDOF_WALK_DEBUG
533 puts("\n-- walk begin --");
534#endif
535
536 /* Sanity check: for rare but possible case (if lib-linking the camera fails). */
537 if ((walk->rv3d->persp == RV3D_CAMOB) && (walk->v3d->camera == nullptr)) {
538 walk->rv3d->persp = RV3D_PERSP;
539 }
540
541 if (walk->rv3d->persp == RV3D_CAMOB &&
543 {
545 RPT_ERROR,
546 "Cannot navigate a camera from an external library or non-editable override");
547 return false;
548 }
549
550 if (ED_view3d_offset_lock_check(walk->v3d, walk->rv3d)) {
551 BKE_report(op->reports, RPT_ERROR, "Cannot navigate when the view offset is locked");
552 return false;
553 }
554
555 if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->constraints.first) {
556 BKE_report(op->reports, RPT_ERROR, "Cannot navigate an object with constraints");
557 return false;
558 }
559
560 walk->state = WALK_RUNNING;
561
562 walk->grid = (walk->scene->unit.system == USER_UNIT_NONE) ?
563 1.0f :
564 1.0f / walk->scene->unit.scale_length;
565
566 const float userdef_jump_height = U.walk_navigation.jump_height * walk->grid;
567 const float userdef_view_height = U.walk_navigation.view_height * walk->grid;
568
569 if (fabsf(U.walk_navigation.walk_speed - g_walk.userdef_speed) > 0.1f) {
570 g_walk.base_speed = U.walk_navigation.walk_speed;
571 g_walk.userdef_speed = U.walk_navigation.walk_speed;
572 }
573
574 if (fabsf(U.walk_navigation.jump_height - g_walk.userdef_jump_height) > 0.1f) {
575 g_walk.jump_height = userdef_jump_height;
576 g_walk.userdef_jump_height = U.walk_navigation.jump_height;
577 }
578
579 walk->jump_height = 0.0f;
580
581 walk->speed = 0.0f;
582 walk->is_fast = false;
583 walk->is_slow = false;
584
585 /* User preference settings. */
586 walk->teleport.duration = U.walk_navigation.teleport_time;
587 walk->mouse_speed = U.walk_navigation.mouse_speed;
588
589 if (U.walk_navigation.flag & USER_WALK_GRAVITY) {
591 }
592 else {
594 }
595
596 walk->view_height = userdef_view_height;
598 walk->speed = U.walk_navigation.walk_speed;
599 walk->speed_factor = U.walk_navigation.walk_speed_factor;
601
603
605 walk->gravity = fabsf(walk->scene->physics_settings.gravity[2]) * walk->grid;
606 }
607 else {
608 walk->gravity = 9.80668f * walk->grid; /* m/s2 */
609 }
610
611 walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
612
613#ifdef USE_TABLET_SUPPORT
614 walk->is_cursor_absolute = false;
615#endif
616
618
619#ifdef NDOF_WALK_DRAW_TOOMUCH
620 walk->redraw = true;
621#endif
622 zero_v3(walk->dvec_prev);
623
624 walk->timer = WM_event_timer_add(CTX_wm_manager(C), win, TIMER, 0.01f);
625
626#ifdef WITH_INPUT_NDOF
627 walk->ndof = nullptr;
628#endif
629
631 walk->need_rotation_keyframe = false;
632 walk->need_translation_keyframe = false;
633
635
638
639 walk->rv3d->rflag |= RV3D_NAVIGATING;
640
642
644 walk->depsgraph, walk->scene, walk->v3d, walk->rv3d);
645
646 copy_v2_v2_int(walk->init_mval, mval);
647 copy_v2_v2_int(walk->prev_mval, mval);
648
650
651 return true;
652}
653
655{
656 wmWindow *win;
657 RegionView3D *rv3d;
658
659 if (walk->state == WALK_RUNNING) {
661 }
662 if (walk->state == WALK_CONFIRM) {
663 /* Needed for auto_keyframe. */
664#ifdef WITH_INPUT_NDOF
665 if (walk->ndof) {
666 walkApply_ndof(C, walk, true);
667 }
668 else
669#endif /* WITH_INPUT_NDOF */
670 {
671 walkApply(C, walk, true);
672 }
673 }
674
675#ifdef NDOF_WALK_DEBUG
676 puts("\n-- walk end --");
677#endif
678
679 win = CTX_wm_window(C);
680 rv3d = walk->rv3d;
681
682 ED_workspace_status_text(C, nullptr);
683
685
687
689
691
692 rv3d->rflag &= ~RV3D_NAVIGATING;
693
694#ifdef WITH_INPUT_NDOF
695 if (walk->ndof) {
696 MEM_freeN(walk->ndof);
697 }
698#endif
699
700 WM_cursor_grab_disable(win, nullptr);
701
702 if (walk->state == WALK_CONFIRM) {
703 MEM_freeN(walk);
704 return OPERATOR_FINISHED;
705 }
706
707 MEM_freeN(walk);
708 return OPERATOR_CANCELLED;
709}
710
711static void walkEvent(WalkInfo *walk, const wmEvent *event)
712{
713 if (event->type == TIMER && event->customdata == walk->timer) {
714 walk->redraw = true;
715 }
716 else if (ISMOUSE_MOTION(event->type)) {
717
718#ifdef USE_TABLET_SUPPORT
719 if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
720 walk->is_cursor_absolute = true;
721 }
722#endif /* USE_TABLET_SUPPORT */
723
724 walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
725 walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
726
727 copy_v2_v2_int(walk->prev_mval, event->mval);
728
729 if (walk->moffset[0] || walk->moffset[1]) {
730 walk->redraw = true;
731 }
732 }
733#ifdef WITH_INPUT_NDOF
734 else if (event->type == NDOF_MOTION) {
735 /* Do these auto-magically get delivered? yes. */
736 // puts("ndof motion detected in walk mode!");
737 // static const char *tag_name = "3D mouse position";
738
739 const wmNDOFMotionData *incoming_ndof = static_cast<const wmNDOFMotionData *>(
740 event->customdata);
741 switch (incoming_ndof->progress) {
742 case P_STARTING: {
743 /* Start keeping track of 3D mouse position. */
744# ifdef NDOF_WALK_DEBUG
745 puts("start keeping track of 3D mouse position");
746# endif
747 /* Fall-through. */
748 }
749 case P_IN_PROGRESS: {
750 /* Update 3D mouse position. */
751# ifdef NDOF_WALK_DEBUG
752 putchar('.');
753 fflush(stdout);
754# endif
755 if (walk->ndof == nullptr) {
756 // walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
757 walk->ndof = static_cast<wmNDOFMotionData *>(MEM_dupallocN(incoming_ndof));
758 // walk->ndof = malloc(sizeof(wmNDOFMotionData));
759 }
760 else {
761 memcpy(walk->ndof, incoming_ndof, sizeof(wmNDOFMotionData));
762 }
763 break;
764 }
765 case P_FINISHING: {
766 /* Stop keeping track of 3D mouse position. */
767# ifdef NDOF_WALK_DEBUG
768 puts("stop keeping track of 3D mouse position");
769# endif
770 if (walk->ndof) {
771 MEM_freeN(walk->ndof);
772 // free(walk->ndof);
773 walk->ndof = nullptr;
774 }
775
776 /* Update the time else the view will jump when 2D mouse/timer resume. */
778
779 break;
780 }
781 default: {
782 /* Should always be one of the above 3. */
783 break;
784 }
785 }
786 }
787#endif /* WITH_INPUT_NDOF */
788 /* Handle modal key-map first. */
789 else if (event->type == EVT_MODAL_MAP) {
790 switch (event->val) {
791 case WALK_MODAL_CANCEL: {
792 walk->state = WALK_CANCEL;
793 break;
794 }
795 case WALK_MODAL_CONFIRM: {
796 walk->state = WALK_CONFIRM;
797 break;
798 }
800 g_walk.base_speed *= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
801 break;
802 }
804 g_walk.base_speed /= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
805 break;
806 }
807 /* Implement WASD keys. */
810 break;
811 }
814 break;
815 }
816 case WALK_MODAL_DIR_LEFT: {
818 break;
819 }
822 break;
823 }
824 case WALK_MODAL_DIR_UP: {
826 break;
827 }
828 case WALK_MODAL_DIR_DOWN: {
830 break;
831 }
834 break;
835 }
838 break;
839 }
842 break;
843 }
846 break;
847 }
850 break;
851 }
854 break;
855 }
858 break;
859 }
862 break;
863 }
866 break;
867 }
870 break;
871 }
873 walk->is_fast = true;
874 break;
875 }
877 walk->is_fast = false;
878 break;
879 }
881 walk->is_slow = true;
882 break;
883 }
885 walk->is_slow = false;
886 break;
887 }
888
889#define JUMP_SPEED_MIN 1.0f
890#define JUMP_TIME_MAX 0.2f /* s */
891#define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height)
892
895 float t;
896
897 /* Delta time. */
899
900 /* Reduce the velocity, if JUMP wasn't hold for long enough. */
901 t = min_ff(t, JUMP_TIME_MAX);
902 walk->speed_jump = JUMP_SPEED_MIN +
904
905 /* When jumping, duration is how long it takes before we start going down. */
907
908 /* No more increase of jump speed. */
910 }
911 break;
912 }
913 case WALK_MODAL_JUMP: {
914 if ((walk->navigation_mode == WALK_MODE_GRAVITY) &&
917 {
918 /* No need to check for ground, `walk->gravity`
919 * wouldn't be off if we were over a hole. */
922
924 copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
925
926 /* Using previous vector because WASD keys are not called when SPACE is. */
928
929 /* When jumping, duration is how long it takes before we start going down. */
931 }
932 break;
933 }
934
935 case WALK_MODAL_TELEPORT: {
936 float loc[3], nor[3];
937 float distance;
938 const bool ret = walk_ray_cast(walk->rv3d, walk, loc, nor, &distance);
939
940 /* In case we are teleporting middle way from a jump. */
941 walk->speed_jump = 0.0f;
942
943 if (ret) {
944 WalkTeleport *teleport = &walk->teleport;
945
946 /* Store the current navigation mode if we are not already teleporting. */
947 if (teleport->state == WALK_TELEPORT_STATE_OFF) {
948 teleport->navigation_mode = walk->navigation_mode;
949 }
950 teleport->state = WALK_TELEPORT_STATE_ON;
952 teleport->duration = U.walk_navigation.teleport_time;
953
955
956 copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
957
958 /* Stop the camera from a distance (camera height). */
960 add_v3_v3(loc, nor);
961
962 sub_v3_v3v3(teleport->direction, loc, teleport->origin);
963 }
964 break;
965 }
966
967#undef JUMP_SPEED_MAX
968#undef JUMP_TIME_MAX
969#undef JUMP_SPEED_MIN
970
972 if (walk->navigation_mode == WALK_MODE_GRAVITY) {
974 }
975 else { /* WALK_MODE_FREE */
977 }
978 break;
979 }
980
982 if (walk->zlock != WALK_AXISLOCK_STATE_DONE) {
984 walk->zlock_momentum = 0.0f;
985 }
986 break;
987 }
988
989#define JUMP_HEIGHT_FACTOR 1.5f
990#define JUMP_HEIGHT_MIN 0.1f
991#define JUMP_HEIGHT_MAX 10.0f
992
994 g_walk.jump_height = min_ff(g_walk.jump_height * JUMP_HEIGHT_FACTOR, JUMP_HEIGHT_MAX);
995 break;
996 }
998 g_walk.jump_height = max_ff(g_walk.jump_height / JUMP_HEIGHT_FACTOR, JUMP_HEIGHT_MIN);
999 break;
1000 }
1001
1002#undef JUMP_HEIGHT_FACTOR
1003#undef JUMP_HEIGHT_MIN
1004#undef JUMP_HEIGHT_MAX
1005 }
1006 }
1007}
1008
1010 WalkInfo *walk,
1011 const bool do_rotate,
1012 const bool do_translate,
1013 const bool is_confirm)
1014{
1015 /* We only consider auto-keying on playback or if user confirmed walk on the same frame
1016 * otherwise we get a keyframe even if the user cancels. */
1017 const bool use_autokey = is_confirm || walk->anim_playing;
1019 walk->v3d_camera_control, use_autokey, C, do_rotate, do_translate);
1020 if (use_autokey) {
1021 walk->need_rotation_keyframe = false;
1022 walk->need_translation_keyframe = false;
1023 }
1024}
1025
1026static float walk_calc_free_fall_distance(const float gravity, const float time)
1027{
1028 return gravity * (time * time) * 0.5f;
1029}
1030
1031static float walk_calc_velocity_zero_time(const float gravity, const float velocity)
1032{
1033 return velocity / gravity;
1034}
1035
1036static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
1037{
1038#define WALK_ROTATE_TABLET_FAC 8.8f /* Higher is faster, relative to region size. */
1039#define WALK_ROTATE_CONSTANT_FAC DEG2RADF(0.15f) /* Higher is faster, radians per-pixel. */
1040#define WALK_TOP_LIMIT DEG2RADF(85.0f)
1041#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
1042#define WALK_MOVE_SPEED (0 ? 0.0f : g_walk.base_speed)
1043#define WALK_JUMP_HEIGHT (0 ? 0.0f : g_walk.jump_height)
1044#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
1045#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
1046#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
1047
1048 RegionView3D *rv3d = walk->rv3d;
1049 ARegion *region = walk->region;
1050
1051 /* 3x3 copy of the view matrix so we can move along the view axis. */
1052 float mat[3][3];
1053 /* This is the direction that's added to the view offset per redraw. */
1054 float dvec[3] = {0.0f, 0.0f, 0.0f};
1055
1056 int moffset[2]; /* Mouse offset from the views center. */
1057 float tmp_quat[4]; /* Used for rotating the view. */
1058
1059#ifdef NDOF_WALK_DEBUG
1060 {
1061 static uint iteration = 1;
1062 printf("walk timer %d\n", iteration++);
1063 }
1064#endif
1065
1066 /* Mouse offset from the center. */
1067 copy_v2_v2_int(moffset, walk->moffset);
1068
1069 /* Apply `moffset` so we can re-accumulate. */
1070 walk->moffset[0] = 0;
1071 walk->moffset[1] = 0;
1072
1073 /* Revert mouse. */
1074 if (walk->is_reversed) {
1075 moffset[1] = -moffset[1];
1076 }
1077
1078 /* Update jump height. */
1081 }
1082
1083 /* Should we redraw? */
1084 if ((walk->active_directions) || moffset[0] || moffset[1] ||
1086 walk->teleport.state == WALK_TELEPORT_STATE_ON || is_confirm)
1087 {
1088 bool changed_viewquat = false;
1089
1090 /* Apply the "scene" grid scale to support navigation around scenes of different sizes. */
1091 bool dvec_grid_scale = true;
1092 float dvec_tmp[3];
1093
1094 /* Time how fast it takes for us to redraw,
1095 * this is so simple scenes don't walk too fast. */
1096 double time_current;
1097 float time_redraw;
1098 float time_redraw_clamped;
1099#ifdef NDOF_WALK_DRAW_TOOMUCH
1100 walk->redraw = true;
1101#endif
1102 time_current = BLI_time_now_seconds();
1103 time_redraw = float(time_current - walk->time_lastdraw);
1104
1105 /* Clamp redraw time to avoid jitter in roll correction. */
1106 time_redraw_clamped = min_ff(0.05f, time_redraw);
1107
1108 walk->time_lastdraw = time_current;
1109
1110 /* Base speed in m/s. */
1111 walk->speed = WALK_MOVE_SPEED;
1112
1113 if (walk->is_fast) {
1114 walk->speed *= WALK_BOOST_FACTOR;
1115 }
1116 else if (walk->is_slow) {
1117 walk->speed *= 1.0f / WALK_BOOST_FACTOR;
1118 }
1119
1120 copy_m3_m4(mat, rv3d->viewinv);
1121
1122 {
1123 /* Rotate about the X axis- look up/down. */
1124 if (moffset[1]) {
1125 float upvec[3];
1126 float angle;
1127 float y;
1128
1129 /* Relative offset. */
1130 y = float(moffset[1]);
1131
1132 /* Speed factor. */
1133#ifdef USE_TABLET_SUPPORT
1134 if (walk->is_cursor_absolute) {
1135 y /= region->winy;
1137 }
1138 else
1139#endif
1140 {
1142 }
1143
1144 /* User adjustment factor. */
1145 y *= walk->mouse_speed;
1146
1147 /* Clamp the angle limits: it ranges from 90.0f to -90.0f. */
1148 angle = -asinf(rv3d->viewmat[2][2]);
1149
1150 if (angle > WALK_TOP_LIMIT && y > 0.0f) {
1151 y = 0.0f;
1152 }
1153 else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f) {
1154 y = 0.0f;
1155 }
1156
1157 copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
1158 mul_m3_v3(mat, upvec);
1159 /* Rotate about the relative up vector. */
1160 axis_angle_to_quat(tmp_quat, upvec, -y);
1161 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
1162 changed_viewquat = true;
1163 }
1164
1165 /* Rotate about the Y axis- look left/right. */
1166 if (moffset[0]) {
1167 float upvec[3];
1168 float x;
1169
1170 /* If we're upside down invert the `moffset`. */
1171 copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f);
1172 mul_m3_v3(mat, upvec);
1173
1174 if (upvec[2] < 0.0f) {
1175 moffset[0] = -moffset[0];
1176 }
1177
1178 /* Relative offset. */
1179 x = float(moffset[0]);
1180
1181 /* Speed factor. */
1182#ifdef USE_TABLET_SUPPORT
1183 if (walk->is_cursor_absolute) {
1184 x /= region->winx;
1186 }
1187 else
1188#endif
1189 {
1191 }
1192
1193 /* User adjustment factor. */
1194 x *= walk->mouse_speed;
1195
1196 /* Rotate about the relative up vector */
1197 axis_angle_to_quat_single(tmp_quat, 'Z', x);
1198 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
1199 changed_viewquat = true;
1200 }
1201
1202 if (walk->zlock == WALK_AXISLOCK_STATE_ACTIVE) {
1203 float upvec[3];
1204 copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
1205 mul_m3_v3(mat, upvec);
1206
1207 /* Make sure we have some Z rolling. */
1208 if (fabsf(upvec[2]) > 0.00001f) {
1209 float roll = upvec[2] * 5.0f;
1210 /* Rotate the view about this axis. */
1211 copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
1212 mul_m3_v3(mat, upvec);
1213 /* Rotate about the relative up vector. */
1214 axis_angle_to_quat(tmp_quat,
1215 upvec,
1216 roll * time_redraw_clamped * walk->zlock_momentum *
1218 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
1219 changed_viewquat = true;
1220
1222 }
1223 else {
1224 /* Lock fixed, don't need to check it ever again. */
1226 }
1227 }
1228 }
1229
1230 /* WASD - 'move' translation code. */
1231 if ((walk->active_directions) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF)) {
1232
1233 short direction;
1234 zero_v3(dvec);
1235
1238 {
1239
1240 direction = 0;
1241
1243 direction += 1;
1244 }
1245
1247 direction -= 1;
1248 }
1249
1250 copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
1251 mul_m3_v3(mat, dvec_tmp);
1252
1253 if (walk->navigation_mode == WALK_MODE_GRAVITY) {
1254 dvec_tmp[2] = 0.0f;
1255 }
1256
1257 add_v3_v3(dvec, dvec_tmp);
1258 }
1259
1260 if ((walk->active_directions & WALK_BIT_LOCAL_LEFT) ||
1262 {
1263
1264 direction = 0;
1265
1267 direction += 1;
1268 }
1269
1271 direction -= 1;
1272 }
1273
1274 dvec_tmp[0] = direction * rv3d->viewinv[0][0];
1275 dvec_tmp[1] = direction * rv3d->viewinv[0][1];
1276 dvec_tmp[2] = 0.0f;
1277
1278 add_v3_v3(dvec, dvec_tmp);
1279 }
1280
1281 /* Up and down movement is only available in free mode, not gravity mode. */
1282 if (walk->navigation_mode == WALK_MODE_FREE) {
1283
1285
1286 direction = 0;
1287
1289 direction -= 1;
1290 }
1291
1293 direction += 1;
1294 }
1295
1296 copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
1297 add_v3_v3(dvec, dvec_tmp);
1298 }
1299
1301
1302 direction = 0;
1303
1305 direction -= 1;
1306 }
1307
1309 direction += 1;
1310 }
1311
1312 madd_v3_v3fl(dvec, rv3d->viewinv[1], direction);
1313 }
1314 }
1315
1316 normalize_v3(dvec);
1317
1318 /* Apply movement. */
1319 mul_v3_fl(dvec, walk->speed * time_redraw);
1320 }
1321
1322 /* Stick to the floor. */
1323 if (walk->navigation_mode == WALK_MODE_GRAVITY &&
1325 {
1326 float ray_distance;
1327 float difference = -100.0f;
1328
1329 if (walk_floor_distance_get(rv3d, walk, dvec, &ray_distance)) {
1330 difference = walk->view_height - ray_distance;
1331 }
1332
1333 /* The distance we would fall naturally smoothly enough that we
1334 * can manually drop the object without activating gravity. */
1335 const float fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR;
1336
1337 if (fabsf(difference) < fall_distance) {
1338 /* slope/stairs */
1339 dvec[2] -= difference;
1340
1341 /* In case we switched from FREE to GRAVITY too close to the ground. */
1344 }
1345 }
1346 else {
1347 /* Hijack the teleport variables. */
1350 walk->teleport.duration = 0.0f;
1351
1352 copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
1353 copy_v2_v2(walk->teleport.direction, dvec);
1354 }
1355 }
1356
1357 /* Falling or jumping). */
1359 float ray_distance, difference = -100.0f;
1360 /* Delta time. */
1361 const float t = float(BLI_time_now_seconds() - walk->teleport.initial_time);
1362
1363 /* Keep moving if we were moving. */
1364 copy_v2_v2(dvec, walk->teleport.direction);
1365
1366 const float z_cur = walk->rv3d->viewinv[3][2] / walk->grid;
1367 const float z_new = ((walk->teleport.origin[2] / walk->grid) -
1369 /* Jump. */
1370 (t * walk->speed_jump);
1371
1372 /* Duration is the jump duration. */
1373 if (t > walk->teleport.duration) {
1374
1375 /* Check to see if we are landing. */
1376 if (walk_floor_distance_get(rv3d, walk, dvec, &ray_distance)) {
1377 difference = walk->view_height - ray_distance;
1378 }
1379
1380 if (difference > 0.0f) {
1381 /* Quit falling, lands at "view_height" from the floor. */
1382 dvec[2] -= difference;
1384 walk->speed_jump = 0.0f;
1385 }
1386 else {
1387 /* Keep falling. */
1388 dvec[2] = z_cur - z_new;
1389 }
1390 }
1391 else {
1392 /* Keep going up (jump). */
1393 dvec[2] = z_cur - z_new;
1394 }
1395 }
1396
1397 /* Teleport. */
1398 else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) {
1399 float t; /* factor */
1400 float new_loc[3];
1401 float cur_loc[3];
1402
1403 /* Linear interpolation. */
1405 t /= walk->teleport.duration;
1406
1407 /* Clamp so we don't go past our limit. */
1408 if (t >= 1.0f) {
1409 t = 1.0f;
1412 }
1413
1414 mul_v3_v3fl(new_loc, walk->teleport.direction, t);
1415 add_v3_v3(new_loc, walk->teleport.origin);
1416
1417 copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]);
1418 sub_v3_v3v3(dvec, cur_loc, new_loc);
1419
1420 /* It doesn't make sense to scale the direction for teleport
1421 * as this value is interpolate between two points. */
1422 dvec_grid_scale = false;
1423 }
1424
1425 /* Scale the movement to the scene size. */
1426 mul_v3_v3fl(dvec_tmp, dvec, dvec_grid_scale ? walk->grid : 1.0f);
1427 add_v3_v3(rv3d->ofs, dvec_tmp);
1428
1429 if (changed_viewquat) {
1430 /* While operations here are expected to keep the quaternion normalized,
1431 * over time floating point error can accumulate error and eventually cause
1432 * it not to be normalized, so - normalize when modified to avoid errors.
1433 * See: #125586. */
1434 normalize_qt(rv3d->viewquat);
1435 }
1436
1437 if (rv3d->persp == RV3D_CAMOB) {
1438 walk->need_rotation_keyframe |= (moffset[0] || moffset[1] ||
1440 walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
1442 C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
1443 }
1444 }
1445 else {
1446 /* We're not redrawing but we need to update the time else the view will jump. */
1448 }
1449 /* End drawing. */
1450 copy_v3_v3(walk->dvec_prev, dvec);
1451
1452 return OPERATOR_FINISHED;
1453#undef WALK_ROTATE_TABLET_FAC
1454#undef WALK_TOP_LIMIT
1455#undef WALK_BOTTOM_LIMIT
1456#undef WALK_MOVE_SPEED
1457#undef WALK_JUMP_HEIGHT
1458#undef WALK_BOOST_FACTOR
1459}
1460
1461#ifdef WITH_INPUT_NDOF
1462static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm)
1463{
1465 bool has_translate, has_rotate;
1466
1467 view3d_ndof_fly(*walk->ndof,
1468 walk->v3d,
1469 walk->rv3d,
1470 walk->is_slow,
1471 lock_ob ? lock_ob->protectflag : 0,
1472 &has_translate,
1473 &has_rotate);
1474
1475 if (has_translate || has_rotate) {
1476 walk->redraw = true;
1477
1478 if (walk->rv3d->persp == RV3D_CAMOB) {
1479 walk->need_rotation_keyframe |= has_rotate;
1480 walk->need_translation_keyframe |= has_translate;
1482 C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
1483 }
1484 }
1485}
1486#endif /* WITH_INPUT_NDOF */
1487
1489
1490/* -------------------------------------------------------------------- */
1493
1495{
1496 WalkInfo *walk = static_cast<WalkInfo *>(op->customdata);
1497
1499
1500 status.opmodal(IFACE_("Confirm"), op->type, WALK_MODAL_CONFIRM);
1501 status.opmodal(IFACE_("Cancel"), op->type, WALK_MODAL_CANCEL);
1502
1503 status.opmodal(
1506 status.opmodal(
1508 status.opmodal(
1510 status.item(IFACE_("Move"), ICON_NONE);
1511
1513 status.opmodal(
1515 status.item(IFACE_("Up/Down"), ICON_NONE);
1516
1517 status.opmodal(
1519 status.opmodal(
1521 status.item(IFACE_("Local Up/Down"), ICON_NONE);
1522
1523 status.opmodal(
1525
1526 status.opmodal(IFACE_("Teleport"),
1527 op->type,
1530
1531 status.opmodal(IFACE_("Fast"), op->type, WALK_MODAL_FAST_ENABLE, walk->is_fast);
1532 status.opmodal(IFACE_("Slow"), op->type, WALK_MODAL_SLOW_ENABLE, walk->is_slow);
1533
1534 status.opmodal(IFACE_("Gravity"),
1535 op->type,
1538
1539 status.opmodal("", op->type, WALK_MODAL_ACCELERATE);
1540 status.opmodal("", op->type, WALK_MODAL_DECELERATE);
1541 status.item(fmt::format("{} ({:.2f})", IFACE_("Acceleration"), g_walk.base_speed), ICON_NONE);
1542
1543 status.opmodal("", op->type, WALK_MODAL_INCREASE_JUMP);
1544 status.opmodal("", op->type, WALK_MODAL_DECREASE_JUMP);
1545 status.item(fmt::format("{} ({:.2f})", IFACE_("Jump Height"), g_walk.jump_height), ICON_NONE);
1546
1547 status.opmodal(IFACE_("Z Axis Correction"),
1548 op->type,
1551}
1552
1554{
1557 return OPERATOR_CANCELLED;
1558 }
1559
1560 WalkInfo *walk = MEM_callocN<WalkInfo>("NavigationWalkOperation");
1561
1562 op->customdata = walk;
1563
1564 if (initWalkInfo(C, walk, op, event->mval) == false) {
1565 MEM_freeN(walk);
1566 return OPERATOR_CANCELLED;
1567 }
1568
1569 walkEvent(walk, event);
1570
1571 walk_draw_status(C, op);
1572
1574
1576}
1577
1579{
1580 WalkInfo *walk = static_cast<WalkInfo *>(op->customdata);
1581
1582 walk->state = WALK_CANCEL;
1583 walkEnd(C, walk);
1584 op->customdata = nullptr;
1585}
1586
1588{
1589 bool do_draw = false;
1590 WalkInfo *walk = static_cast<WalkInfo *>(op->customdata);
1591 ARegion *region = walk->region;
1592 View3D *v3d = walk->v3d;
1593 RegionView3D *rv3d = walk->rv3d;
1595
1596 walk->redraw = false;
1597
1598 walkEvent(walk, event);
1599
1600 walk_draw_status(C, op);
1601
1602#ifdef WITH_INPUT_NDOF
1603 if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer]. */
1604 if (event->type == NDOF_MOTION) {
1605 walkApply_ndof(C, walk, false);
1606 }
1607 }
1608 else
1609#endif /* WITH_INPUT_NDOF */
1610 {
1611 if (event->type == TIMER && event->customdata == walk->timer) {
1612 walkApply(C, walk, false);
1613 }
1614 }
1615
1616 do_draw |= walk->redraw;
1617
1618 const wmOperatorStatus exit_code = walkEnd(C, walk);
1619
1620 if (exit_code != OPERATOR_RUNNING_MODAL) {
1621 do_draw = true;
1622 }
1623 if (exit_code == OPERATOR_FINISHED) {
1624 const bool is_undo_pushed = ED_view3d_camera_lock_undo_push(op->type->name, v3d, rv3d, C);
1625 /* If generic 'locked camera' code did not push an undo, but there is a valid 'walking
1626 * object', an undo push is still needed, since that object transform was modified. */
1627 if (!is_undo_pushed && walk_object && ED_undo_is_memfile_compatible(C)) {
1628 ED_undo_push(C, op->type->name);
1629 }
1630 }
1631
1632 if (do_draw) {
1633 if (rv3d->persp == RV3D_CAMOB) {
1635 }
1636
1637 /* Too frequent, commented with `NDOF_WALK_DRAW_TOOMUCH` for now. */
1638 // puts("redraw!");
1639 ED_region_tag_redraw(region);
1640 }
1641 return exit_code;
1642}
1643
1645{
1646 /* Identifiers. */
1647 ot->name = "Walk Navigation";
1648 ot->description = "Interactively walk around the scene";
1649 ot->idname = "VIEW3D_OT_walk";
1650
1651 /* API callbacks. */
1652 ot->invoke = walk_invoke;
1653 ot->cancel = walk_cancel;
1654 ot->modal = walk_modal;
1656
1657 /* flags */
1658 /* NOTE: #OPTYPE_BLOCKING isn't used because this needs to grab & hide the cursor.
1659 * where as blocking confines the cursor to the window bounds, even when hidden. */
1660 ot->flag = 0;
1661}
1662
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BVH_RAYCAST_DIST_MAX
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
void mul_m3_v3(const float M[3][3], float r[3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void axis_angle_to_quat_single(float q[4], char axis, float angle)
float normalize_qt(float q[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_length(float n[3], float unit_length)
MINLINE float normalize_v3(float n[3])
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define ENUM_OPERATORS(_type, _max)
#define ELEM(...)
#define IFACE_(msgid)
Object is a sort of wrapper for general info.
@ PHYS_GLOBAL_GRAVITY
@ SCE_SNAP_TARGET_ALL
@ USER_UNIT_NONE
@ USER_WALK_MOUSE_REVERSE
@ USER_WALK_GRAVITY
#define RV3D_LOCK_FLAGS(rv3d)
@ RV3D_NAVIGATING
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_LOCK_ANY_TRANSFORM
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
bool ED_operator_region_view3d_active(bContext *C)
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define REGION_DRAW_POST_PIXEL
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
bool ED_undo_is_memfile_compatible(const bContext *C)
Definition ed_undo.cc:387
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
bool ED_view3d_camera_lock_undo_push(const char *str, const View3D *v3d, const RegionView3D *rv3d, bContext *C)
void ED_view3d_calc_camera_border(const Scene *scene, const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const RegionView3D *rv3d, bool no_shift, rctf *r_viewborder)
void immUniformThemeColorAlpha(int color_id, float a)
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex2f(uint attr_id, float x, float y)
GPUVertFormat * immVertexFormat()
void immBegin(GPUPrimType, uint vertex_len)
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_UNIFORM_COLOR
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ TH_VIEW_OVERLAY
#define ND_TRANSFORM
Definition WM_types.hh:456
#define NC_OBJECT
Definition WM_types.hh:379
@ P_IN_PROGRESS
Definition WM_types.hh:853
@ P_STARTING
Definition WM_types.hh:852
@ P_FINISHING
Definition WM_types.hh:854
@ WM_CURSOR_WRAP_NONE
Definition WM_types.hh:226
#define U
nullptr float
#define asinf(x)
uint pos
uint nor
#define printf(...)
float distance(VecOp< float, D >, VecOp< float, D >) RET
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void snap_object_context_destroy(SnapObjectContext *sctx)
SnapObjectContext * snap_object_context_create(Scene *scene, int flag)
bool snap_object_project_ray(SnapObjectContext *sctx, Depsgraph *depsgraph, const View3D *v3d, const SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_co[3], float r_no[3])
const int status
return ret
#define fabsf
ARegionRuntimeHandle * runtime
void * first
ListBase constraints
short protectflag
float viewmat[4][4]
float viewinv[4][4]
struct PhysicsSettings physics_settings
struct UnitSettings unit
struct Object * camera
Depsgraph * depsgraph
eWalkMethod navigation_mode
WalkTeleport teleport
eWalkDirectionFlag active_directions
eWalkGravityState gravity_state
View3DCameraControl * v3d_camera_control
eWalkLockState zlock
blender::ed::transform::SnapObjectContext * snap_context
RegionView3D * rv3d
eWalkMethod navigation_mode
eWalkTeleportState state
float xmin
float ymin
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
wmTabletData tablet
Definition WM_types.hh:786
void * customdata
Definition WM_types.hh:807
const void * modal_items
const char * name
Definition WM_types.hh:1033
struct ReportList * reports
struct wmOperatorType * type
char is_motion_absolute
Definition WM_types.hh:712
View3DCameraControl * ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d)
Object * ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, const bool use_autokey, bContext *C, const bool do_rotate, const bool do_translate)
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
static void walk_draw_status(bContext *C, wmOperator *op)
static void walkMoveCamera(bContext *C, WalkInfo *walk, const bool do_rotate, const bool do_translate, const bool is_confirm)
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int mval[2])
float userdef_jump_height
#define WALK_JUMP_HEIGHT
static bool walk_floor_distance_get(RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance)
#define WALK_ROTATE_TABLET_FAC
#define JUMP_SPEED_MAX
#define WALK_MOVE_SPEED
static void walkEvent(WalkInfo *walk, const wmEvent *event)
float jump_height
#define WALK_ROTATE_CONSTANT_FAC
@ WALK_TELEPORT_STATE_ON
@ WALK_TELEPORT_STATE_OFF
static wmOperatorStatus walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@ WALK_MODAL_DECELERATE
@ WALK_MODAL_DIR_LOCAL_DOWN
@ WALK_MODAL_JUMP
@ WALK_MODAL_DIR_LEFT_STOP
@ WALK_MODAL_SLOW_DISABLE
@ WALK_MODAL_DIR_RIGHT
@ WALK_MODAL_SLOW_ENABLE
@ WALK_MODAL_DIR_LOCAL_UP
@ WALK_MODAL_DIR_DOWN_STOP
@ WALK_MODAL_DECREASE_JUMP
@ WALK_MODAL_INCREASE_JUMP
@ WALK_MODAL_CONFIRM
@ WALK_MODAL_DIR_LEFT
@ WALK_MODAL_FAST_ENABLE
@ WALK_MODAL_DIR_BACKWARD
@ WALK_MODAL_TELEPORT
@ WALK_MODAL_DIR_FORWARD_STOP
@ WALK_MODAL_DIR_UP
@ WALK_MODAL_JUMP_STOP
@ WALK_MODAL_DIR_DOWN
@ WALK_MODAL_GRAVITY_TOGGLE
@ WALK_MODAL_DIR_FORWARD
@ WALK_MODAL_DIR_BACKWARD_STOP
@ WALK_MODAL_DIR_RIGHT_STOP
@ WALK_MODAL_CANCEL
@ WALK_MODAL_ACCELERATE
@ WALK_MODAL_DIR_UP_STOP
@ WALK_MODAL_DIR_LOCAL_DOWN_STOP
@ WALK_MODAL_DIR_LOCAL_UP_STOP
@ WALK_MODAL_AXIS_LOCK_Z
@ WALK_MODAL_FAST_DISABLE
void VIEW3D_OT_walk(wmOperatorType *ot)
float userdef_speed
@ WALK_GRAVITY_STATE_START
@ WALK_GRAVITY_STATE_JUMP
@ WALK_GRAVITY_STATE_OFF
@ WALK_GRAVITY_STATE_ON
#define JUMP_TIME_MAX
@ WALK_MODE_GRAVITY
static wmOperatorStatus walkEnd(bContext *C, WalkInfo *walk)
#define JUMP_HEIGHT_MAX
static void walk_cancel(bContext *C, wmOperator *op)
#define WALK_TOP_LIMIT
static float walk_calc_free_fall_distance(const float gravity, const float time)
static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
#define WALK_ZUP_CORRECT_ACCEL
static wmOperatorStatus walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
static float walk_calc_velocity_zero_time(const float gravity, const float velocity)
static void drawWalkPixel(const bContext *, ARegion *region, void *arg)
#define WALK_ZUP_CORRECT_FAC
@ WALK_AXISLOCK_STATE_DONE
@ WALK_AXISLOCK_STATE_OFF
@ WALK_AXISLOCK_STATE_ACTIVE
@ WALK_BIT_LOCAL_LEFT
@ WALK_BIT_GLOBAL_DOWN
@ WALK_BIT_LOCAL_RIGHT
@ WALK_BIT_GLOBAL_UP
@ WALK_BIT_LOCAL_FORWARD
@ WALK_BIT_LOCAL_DOWN
@ WALK_BIT_LOCAL_UP
@ WALK_BIT_LOCAL_BACKWARD
#define WALK_BOOST_FACTOR
#define JUMP_HEIGHT_FACTOR
void walk_modal_keymap(wmKeyConfig *keyconf)
static bool walk_ray_cast(RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *r_ray_distance)
static struct @372060135224246136017363062057302243322267243331 g_walk
#define JUMP_HEIGHT_MIN
#define JUMP_SPEED_MIN
float base_speed
static void walk_navigation_mode_set(WalkInfo *walk, eWalkMethod mode)
#define WALK_BOTTOM_LIMIT
void WM_cursor_grab_enable(wmWindow *win, const eWM_CursorWrapAxis wrap, const rcti *wrap_region, const bool hide)
void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
#define ISMOUSE_MOTION(event_type)
@ TIMER
@ EVT_MODAL_MAP
@ NDOF_MOTION
wmOperatorType * ot
Definition wm_files.cc:4237
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:932
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:959
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)