Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDalai Felinto <dfelinto@gmail.com>2013-12-03 09:14:09 +0400
committerDalai Felinto <dfelinto@gmail.com>2013-12-03 09:14:09 +0400
commitab494379586034a6844c858324815e3b1ff3cbb2 (patch)
tree88ee6a460649f4488d72ad0e97e6d8839cc6132f
parent2e4601c35629f6b221a9e9fd2eaa2efb4fd092ab (diff)
View Navigation: Walk and Fly modes
This is a addtion to the dynamic fly mode. It behaves as the first person navigation system available in most 3d world games nowadays. You can alternate between the old mode (Fly) and the new mode (Walk) in User Preferences > Inputs Manual: ------- http://wiki.blender.org/index.php/Doc:2.6/Manual/3D_interaction/Navigating/3D_View#View_Navigation http://wiki.blender.org/index.php/Doc:2.6/Manual/3D_interaction/Navigating/3D_View/Navigation_Modes Shortcuts: ---------- WASD (hold) - Move forward/backward and straft left/right QE (hold) - Move up and down Tab - Alternate between Walk and Fly modes Shift (hold) - Speed up movement Alt (hold) - Slow down movement Space or MMB - Teleport V - Jump +/- or mouse wheel - speed increase/decrease speed for this Blender session User Preferences Options: ------------------------- Navigation Mode - fly/walk navigation systems (fly is the old, walk is the new, next options are for walk mode only) Gravity - alternate between free navigation and walk with gravity modes Mouse Sensitivity - sensitivity factor to mouse influence to look around Teleport Duration - how long the teleport lasts Camera Height - camera height to use in gravity mode Jump Height - maximum jump speed in m/s Move Speed - base move speed in m/s Boost Factor - multiplication factor when running or going slow (1/boost) Development Notes: ------------------ * The initial code was based on view3d_fly.c. * The NDoF code was not touched, so it most likely is not working. Pending Issues: --------------- * Draw in the UI the shortcut options, and current values (e.g., Mode: Fly/Walk) (we need a proper API for that) * OSX seems to present issues if we re-center the mouse every time. We implemented a workaround for that, but a real fix would be welcome. Code reviewed and with collaborations from Campbell Barton - @campbellbarton Differential Revision: http://developer.blender.org/D30
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py22
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--source/blender/blenloader/intern/readfile.c12
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c29
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h5
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c1419
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h27
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c66
12 files changed, 1586 insertions, 4 deletions
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 17a3e8bf0b8..acd4fc87de4 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1053,6 +1053,28 @@ class USERPREF_PT_input(Panel):
col.separator()
sub = col.column()
+ sub.label(text="View Navigation:")
+ sub.row().prop(inputs, "navigation_mode", expand=True)
+ if inputs.navigation_mode == 'WALK':
+ walk = inputs.walk_navigation
+
+ sub.prop(walk, "use_mouse_reverse")
+ sub.prop(walk, "mouse_speed")
+ sub.prop(walk, "teleport_time")
+
+ sub = col.column(align=True)
+ sub.prop(walk, "walk_speed")
+ sub.prop(walk, "walk_speed_factor")
+
+ sub.separator()
+ sub.prop(walk, "use_gravity")
+ sub = col.column(align=True)
+ sub.active = walk.use_gravity
+ sub.prop(walk, "view_height")
+ sub.prop(walk, "jump_height")
+
+ col.separator()
+ sub = col.column()
sub.label(text="NDOF Device:")
sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity")
sub.prop(inputs, "ndof_orbit_sensitivity", text="NDOF Orbit Sensitivity")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 74d274a8896..dd3710fe8e8 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -435,6 +435,7 @@ class VIEW3D_MT_view_navigation(Menu):
layout.separator()
layout.operator("view3d.fly")
+ layout.operator("view3d.walk")
class VIEW3D_MT_view_align(Menu):
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c6cf32c9477..047dc3609c7 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -7385,7 +7385,7 @@ static void convert_tface_mt(FileData *fd, Main *main)
/* initialize userdef with non-UI dependency stuff */
/* other initializers (such as theme color defaults) go to resources.c */
-static void do_versions_userdef(FileData *UNUSED(fd), BlendFileData *bfd)
+static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
{
Main *bmain = bfd->main;
UserDef *user = bfd->user;
@@ -7401,6 +7401,16 @@ static void do_versions_userdef(FileData *UNUSED(fd), BlendFileData *bfd)
copy_v4_v4_char(btheme->tseq.grid, btheme->tseq.back);
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "WalkNavigation", "walk_navigation")) {
+ user->walk_navigation.mouse_speed = 1.0f;
+ user->walk_navigation.walk_speed = 2.5f; /* m/s */
+ user->walk_navigation.walk_speed_factor = 5.0f;
+ user->walk_navigation.view_height = 1.6f; /* m */
+ user->walk_navigation.jump_height = 0.4f; /* m */
+ user->walk_navigation.teleport_time = 0.2f; /* s */
+ }
+
}
static void do_versions(FileData *fd, Library *lib, Main *main)
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index af89c5307b6..51477ec2ae7 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
view3d_draw.c
view3d_edit.c
view3d_fly.c
+ view3d_walk.c
view3d_header.c
view3d_iterators.c
view3d_ops.c
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 372f87253a3..ea335f7b43f 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3889,6 +3889,35 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot)
ot->flag = 0;
}
+static int view3d_navigate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ eViewNavigation_Method mode = U.navigation_mode;
+
+ switch (mode) {
+ case VIEW_NAVIGATION_FLY:
+ WM_operator_name_call(C, "VIEW3D_OT_fly", WM_OP_INVOKE_DEFAULT, NULL);
+ break;
+ case VIEW_NAVIGATION_WALK:
+ default:
+ WM_operator_name_call(C, "VIEW3D_OT_walk", WM_OP_INVOKE_DEFAULT, NULL);
+ break;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_navigate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Navigation";
+ ot->description = "Interactively navigate around the scene. It uses the mode (walk/fly) preference";
+ ot->idname = "VIEW3D_OT_navigate";
+
+ /* api callbacks */
+ ot->invoke = view3d_navigate_invoke;
+ ot->poll = ED_operator_view3d_active;
+}
+
/* ******************** add background image operator **************** */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 9bca5345e82..fae7804f31b 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -92,6 +92,7 @@ void VIEW3D_OT_view_center_camera(struct wmOperatorType *ot);
void VIEW3D_OT_view_center_lock(struct wmOperatorType *ot);
void VIEW3D_OT_view_pan(struct wmOperatorType *ot);
void VIEW3D_OT_view_persportho(struct wmOperatorType *ot);
+void VIEW3D_OT_navigate(struct wmOperatorType *ot);
void VIEW3D_OT_background_image_add(struct wmOperatorType *ot);
void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot);
void VIEW3D_OT_view_orbit(struct wmOperatorType *ot);
@@ -112,6 +113,9 @@ float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void view3d_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_fly(struct wmOperatorType *ot);
+/* view3d_walk.c */
+void VIEW3D_OT_walk(struct wmOperatorType *ot);
+
/* view3d_ruler.c */
void VIEW3D_OT_ruler(struct wmOperatorType *ot);
@@ -195,6 +199,7 @@ void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect);
void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
+void walk_modal_keymap(struct wmKeyConfig *keyconf);
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 111b2ea3143..12405150267 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -172,6 +172,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_localview);
WM_operatortype_append(VIEW3D_OT_game_start);
WM_operatortype_append(VIEW3D_OT_fly);
+ WM_operatortype_append(VIEW3D_OT_walk);
+ WM_operatortype_append(VIEW3D_OT_navigate);
WM_operatortype_append(VIEW3D_OT_ruler);
WM_operatortype_append(VIEW3D_OT_layers);
WM_operatortype_append(VIEW3D_OT_copybuffer);
@@ -224,7 +226,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_to_active", PADPERIOD, KM_PRESS, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_clear", PADPERIOD, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_fly", FKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_verify_item(keymap, "VIEW3D_OT_navigate", FKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
@@ -504,6 +506,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
transform_keymap_for_space(keyconf, keymap, SPACE_VIEW3D);
fly_modal_keymap(keyconf);
+ walk_modal_keymap(keyconf);
viewrotate_modal_keymap(keyconf);
viewmove_modal_keymap(keyconf);
viewzoom_modal_keymap(keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
new file mode 100644
index 00000000000..26f942b3ecd
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -0,0 +1,1419 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * Contributor(s): Dalai Felinto, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_walk.c
+ * \ingroup spview3d
+ */
+
+/* defines VIEW3D_OT_navigate - walk modal operator */
+
+//#define NDOF_WALK_DEBUG
+//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "BIF_gl.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform.h"
+
+#include "PIL_time.h" /* smoothview */
+
+#include "view3d_intern.h" /* own include */
+
+#define EARTH_GRAVITY 9.80668f /* m/s2 */
+
+/* prototypes */
+static float getVelocityZeroTime(float velocity);
+
+/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
+enum {
+ WALK_MODAL_CANCEL = 1,
+ WALK_MODAL_CONFIRM,
+ WALK_MODAL_DIR_FORWARD,
+ WALK_MODAL_DIR_FORWARD_STOP,
+ WALK_MODAL_DIR_BACKWARD,
+ WALK_MODAL_DIR_BACKWARD_STOP,
+ WALK_MODAL_DIR_LEFT,
+ WALK_MODAL_DIR_LEFT_STOP,
+ WALK_MODAL_DIR_RIGHT,
+ WALK_MODAL_DIR_RIGHT_STOP,
+ WALK_MODAL_DIR_UP,
+ WALK_MODAL_DIR_UP_STOP,
+ WALK_MODAL_DIR_DOWN,
+ WALK_MODAL_DIR_DOWN_STOP,
+ WALK_MODAL_FAST_ENABLE,
+ WALK_MODAL_FAST_DISABLE,
+ WALK_MODAL_SLOW_ENABLE,
+ WALK_MODAL_SLOW_DISABLE,
+ WALK_MODAL_JUMP,
+ WALK_MODAL_JUMP_STOP,
+ WALK_MODAL_TELEPORT,
+ WALK_MODAL_TOGGLE,
+ WALK_MODAL_ACCELERATE,
+ WALK_MODAL_DECELERATE,
+};
+
+enum {
+ WALK_BIT_FORWARD = 1 << 0,
+ WALK_BIT_BACKWARD = 1 << 1,
+ WALK_BIT_LEFT = 1 << 2,
+ WALK_BIT_RIGHT = 1 << 3,
+ WALK_BIT_UP = 1 << 4,
+ WALK_BIT_DOWN = 1 << 5,
+};
+
+typedef enum eWalkTeleportState {
+ WALK_TELEPORT_STATE_OFF = 0,
+ WALK_TELEPORT_STATE_ON,
+} eWalkTeleportState;
+
+typedef enum eWalkMethod {
+ WALK_MODE_FREE = 0,
+ WALK_MODE_GRAVITY,
+} eWalkMethod;
+
+typedef enum eWalkGravityState {
+ WALK_GRAVITY_STATE_OFF = 0,
+ WALK_GRAVITY_STATE_JUMP,
+ WALK_GRAVITY_STATE_START,
+ WALK_GRAVITY_STATE_ON,
+} eWalkGravityState;
+
+/* called in transform_ops.c, on each regeneration of keymaps */
+void walk_modal_keymap(wmKeyConfig *keyconf)
+{
+ static EnumPropertyItem modal_items[] = {
+ {WALK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {WALK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
+
+ {WALK_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""},
+ {WALK_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
+
+ {WALK_MODAL_DIR_FORWARD, "FORWARD", 0, "Move Forward", ""},
+ {WALK_MODAL_DIR_BACKWARD, "BACKWARD", 0, "Move Backward", ""},
+ {WALK_MODAL_DIR_LEFT, "LEFT", 0, "Move Left (Strafe)", ""},
+ {WALK_MODAL_DIR_RIGHT, "RIGHT", 0, "Move Right (Strafe)", ""},
+ {WALK_MODAL_DIR_UP, "UP", 0, "Move Up", ""},
+ {WALK_MODAL_DIR_DOWN, "DOWN", 0, "Move Down", ""},
+
+ {WALK_MODAL_DIR_FORWARD_STOP, "FORWARD_STOP", 0, "Stop Move Forward", ""},
+ {WALK_MODAL_DIR_BACKWARD_STOP, "BACKWARD_STOP", 0, "Stop Mode Backward", ""},
+ {WALK_MODAL_DIR_LEFT_STOP, "LEFT_STOP", 0, "Stop Move Left", ""},
+ {WALK_MODAL_DIR_RIGHT_STOP, "RIGHT_STOP", 0, "Stop Mode Right", ""},
+ {WALK_MODAL_DIR_UP_STOP, "UP_STOP", 0, "Stop Move Up", ""},
+ {WALK_MODAL_DIR_DOWN_STOP, "DOWN_STOP", 0, "Stop Mode Down", ""},
+
+ {WALK_MODAL_TELEPORT, "TELEPORT", 0, "Teleport", "Move forward a few units at once"},
+
+ {WALK_MODAL_FAST_ENABLE, "FAST_ENABLE", 0, "Fast Enable", "Move faster (walk or fly)"},
+ {WALK_MODAL_FAST_DISABLE, "FAST_DISABLE", 0, "Fast Disable", "Resume regular speed"},
+
+ {WALK_MODAL_SLOW_ENABLE, "SLOW_ENABLE", 0, "Slow Enable", "Move slower (walk or fly)"},
+ {WALK_MODAL_SLOW_DISABLE, "SLOW_DISABLE", 0, "Slow Disable", "Resume regular speed"},
+
+ {WALK_MODAL_JUMP, "JUMP", 0, "Jump", "Jump when in walk mode"},
+ {WALK_MODAL_JUMP_STOP, "JUMP_STOP", 0, "Jump Stop", "Stop pushing jump"},
+
+ {0, NULL, 0, NULL, NULL}};
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Walk Modal");
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap && keymap->modal_items)
+ return;
+
+ keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CANCEL);
+
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM);
+
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_FAST_ENABLE);
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_FAST_DISABLE);
+
+ WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_SLOW_ENABLE);
+ WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_SLOW_DISABLE);
+
+ /* WASD */
+ WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_FORWARD);
+ WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD);
+ WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_LEFT);
+ WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_RIGHT);
+ WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_UP);
+ WM_modalkeymap_add_item(keymap, QKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_DOWN);
+
+ WM_modalkeymap_add_item(keymap, WKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP);
+ WM_modalkeymap_add_item(keymap, SKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP);
+ WM_modalkeymap_add_item(keymap, AKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP);
+ WM_modalkeymap_add_item(keymap, DKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP);
+ WM_modalkeymap_add_item(keymap, EKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_UP_STOP);
+ WM_modalkeymap_add_item(keymap, QKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_DOWN_STOP);
+
+ WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_FORWARD);
+ WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_BACKWARD);
+ WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_LEFT);
+ WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_RIGHT);
+
+ WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP);
+ WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP);
+ WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP);
+ WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP);
+
+ WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE);
+ WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE);
+
+ WM_modalkeymap_add_item(keymap, VKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_JUMP);
+ WM_modalkeymap_add_item(keymap, VKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_JUMP_STOP);
+
+ WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_TELEPORT);
+ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_TELEPORT);
+
+ WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE);
+ WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE);
+ WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE);
+ WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE);
+
+ /* assign map to operators */
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk");
+}
+
+
+typedef struct WalkTeleport
+{
+ eWalkTeleportState state;
+ float duration; /* from user preferences */
+ float origin[3];
+ float direction[3];
+ double initial_time;
+ eWalkMethod navigation_mode; /* teleport always set FREE mode on */
+
+} WalkTeleport;
+
+typedef struct WalkInfo {
+ /* context stuff */
+ RegionView3D *rv3d;
+ View3D *v3d;
+ ARegion *ar;
+ Scene *scene;
+
+ wmTimer *timer; /* needed for redraws */
+
+ short state;
+ bool redraw;
+
+ int prev_mval[2]; /* previous 2D mouse values */
+ int center_mval[2]; /* center mouse values */
+ int moffset[2];
+ wmNDOFMotionData *ndof; /* latest 3D mouse values */
+
+ /* walk state state */
+ float base_speed; /* the base speed without run/slow down modifications */
+ float speed; /* the speed the view is moving per redraw */
+ float grid; /* world scale 1.0 default */
+
+ /* compare between last state */
+ double time_lastdraw; /* time between draws */
+
+ void *draw_handle_pixel;
+
+ /* use for some lag */
+ float dvec_prev[3]; /* old for some lag */
+
+ /* walk/fly */
+ eWalkMethod navigation_mode;
+
+ /* teleport */
+ WalkTeleport teleport;
+
+ /* look speed factor - user preferences */
+ float mouse_speed;
+
+ /* speed adjustments */
+ bool is_fast;
+ bool is_slow;
+
+ /* mouse reverse */
+ bool is_reversed;
+
+ /* gravity system */
+ eWalkGravityState gravity;
+
+ /* height to use in walk mode */
+ float view_height;
+
+ /* counting system to allow movement to continue if a direction (WASD) key is still pressed */
+ int active_directions;
+
+ float speed_jump;
+ float jump_height; /* maximum jump height */
+ float speed_factor; /* to use for fast/slow speeds */
+
+ struct View3DCameraControl *v3d_camera_control;
+
+} WalkInfo;
+
+static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg)
+{
+ /* draws an aim/cross in the center */
+ WalkInfo *walk = arg;
+
+ const int outter_length = 24;
+ const int inner_length = 14;
+ int xoff, yoff;
+ rctf viewborder;
+
+ if (walk->scene->camera) {
+ ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false);
+ xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f;
+ yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f;
+ }
+ else {
+ xoff = walk->ar->winx / 2;
+ yoff = walk->ar->winy / 2;
+ }
+
+ cpack(0);
+
+ glBegin(GL_LINES);
+ /* North */
+ glVertex2i(xoff, yoff + inner_length);
+ glVertex2i(xoff, yoff + outter_length);
+
+ /* East */
+ glVertex2i(xoff + inner_length, yoff);
+ glVertex2i(xoff + outter_length, yoff);
+
+ /* South */
+ glVertex2i(xoff, yoff - inner_length);
+ glVertex2i(xoff, yoff - outter_length);
+
+ /* West */
+ glVertex2i(xoff - inner_length, yoff);
+ glVertex2i(xoff - outter_length, yoff);
+ glEnd();
+
+ /* XXX print shortcuts for modal options, and current values */
+}
+
+static void walk_navigation_mode_set(WalkInfo *walk, eWalkMethod mode)
+{
+ if (mode == WALK_MODE_FREE) {
+ walk->navigation_mode = WALK_MODE_FREE;
+ walk->gravity = WALK_GRAVITY_STATE_OFF;
+ }
+ else { /* WALK_MODE_GRAVITY */
+ walk->navigation_mode = WALK_MODE_GRAVITY;
+ walk->gravity = WALK_GRAVITY_STATE_START;
+ }
+}
+
+/**
+ * \param ray_distance Distance to the hit point
+ */
+static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float dvec[3], float *ray_distance)
+{
+ float dummy_dist_px = 0;
+ float ray_normal[3] = {0, 0, -1}; /* down */
+ float ray_start[3];
+ float r_location[3];
+ float r_normal[3];
+ float dvec_tmp[3];
+ bool ret;
+
+ *ray_distance = TRANSFORM_DIST_MAX_RAY;
+
+ copy_v3_v3(ray_start, rv3d->viewinv[3]);
+
+ if (dvec) {
+ mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
+ add_v3_v3(ray_start, dvec_tmp);
+ }
+
+ ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
+ NULL, NULL,
+ ray_start, ray_normal, ray_distance,
+ NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL);
+
+ /* artifically scale the distance to the scene size */
+ *ray_distance /= walk->grid;
+ return ret;
+}
+
+/**
+ * \param ray_distance Distance to the hit point
+ * \param r_location Location of the hit point
+ * \param r_normal Normal of the hit surface, transformed to always face the camera
+ */
+static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance)
+{
+ float dummy_dist_px = 0;
+ float ray_normal[3] = {0, 0, 1}; /* forward */
+ float ray_start[3];
+ float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
+ bool ret;
+
+ *ray_distance = TRANSFORM_DIST_MAX_RAY;
+
+ copy_v3_v3(ray_start, rv3d->viewinv[3]);
+ copy_m3_m4(mat, rv3d->viewinv);
+
+ mul_m3_v3(mat, ray_normal);
+
+ mul_v3_fl(ray_normal, -1);
+ normalize_v3(ray_normal);
+
+ ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
+ NULL, NULL,
+ ray_start, ray_normal, ray_distance,
+ NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL);
+
+
+ /* dot is positive if both rays are facing the same direction */
+ if (dot_v3v3(ray_normal, r_normal) > 0) {
+ copy_v3_fl3(r_normal, -r_normal[0], -r_normal[1], -r_normal[2]);
+ }
+
+ /* artifically scale the distance to the scene size */
+ *ray_distance /= walk->grid;
+
+ return ret;
+}
+
+/* WalkInfo->state */
+enum {
+ WALK_RUNNING = 0,
+ WALK_CANCEL = 1,
+ WALK_CONFIRM = 2,
+};
+
+/* keep the previous speed until user changes userpreferences */
+static float base_speed = -1.f;
+static float userdef_speed = -1.f;
+
+static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ walk->rv3d = CTX_wm_region_view3d(C);
+ walk->v3d = CTX_wm_view3d(C);
+ walk->ar = CTX_wm_region(C);
+ walk->scene = CTX_data_scene(C);
+
+#ifdef NDOF_WALK_DEBUG
+ puts("\n-- walk begin --");
+#endif
+
+ /* sanity check: for rare but possible case (if lib-linking the camera fails) */
+ if ((walk->rv3d->persp == RV3D_CAMOB) && (walk->v3d->camera == NULL)) {
+ walk->rv3d->persp = RV3D_PERSP;
+ }
+
+ if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->id.lib) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot navigate a camera from an external library");
+ return false;
+ }
+
+ if (ED_view3d_offset_lock_check(walk->v3d, walk->rv3d)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot navigate when the view offset is locked");
+ return false;
+ }
+
+ if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->constraints.first) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot navigate an object with constraints");
+ return false;
+ }
+
+ walk->state = WALK_RUNNING;
+
+ if (fabsf(U.walk_navigation.walk_speed - userdef_speed) > 0.1f) {
+ base_speed = U.walk_navigation.walk_speed;
+ userdef_speed = U.walk_navigation.walk_speed;
+ }
+
+ walk->speed = 0.0f;
+ walk->is_fast = false;
+ walk->is_slow = false;
+ walk->grid = 1.f / walk->scene->unit.scale_length;
+
+ /* user preference settings */
+ walk->teleport.duration = U.walk_navigation.teleport_time;
+ walk->mouse_speed = U.walk_navigation.mouse_speed;
+
+ if ((U.walk_navigation.flag & USER_WALK_GRAVITY))
+ walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
+ else
+ walk_navigation_mode_set(walk, WALK_MODE_FREE);
+
+ walk->view_height = U.walk_navigation.view_height;
+ walk->jump_height = U.walk_navigation.jump_height;
+ walk->speed = U.walk_navigation.walk_speed;
+ walk->speed_factor = U.walk_navigation.walk_speed_factor;
+
+ walk->gravity = WALK_GRAVITY_STATE_OFF;
+
+ walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
+
+ walk->active_directions = 0;
+
+#ifdef NDOF_WALK_DRAW_TOOMUCH
+ walk->redraw = 1;
+#endif
+ zero_v3(walk->dvec_prev);
+
+ walk->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f);
+
+ walk->ndof = NULL;
+
+ walk->time_lastdraw = PIL_check_seconds_timer();
+
+ walk->draw_handle_pixel = ED_region_draw_cb_activate(walk->ar->type, drawWalkPixel, walk, REGION_DRAW_POST_PIXEL);
+
+ walk->rv3d->rflag |= RV3D_NAVIGATING;
+
+
+ walk->v3d_camera_control = ED_view3d_cameracontrol_aquire(
+ walk->scene, walk->v3d, walk->rv3d,
+ (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
+
+ /* center the mouse */
+ walk->center_mval[0] = walk->ar->winx * 0.5f;
+ walk->center_mval[1] = walk->ar->winy * 0.5f;
+
+ copy_v2_v2_int(walk->prev_mval, walk->center_mval);
+
+ WM_cursor_warp(CTX_wm_window(C),
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+
+ /* remove the mouse cursor temporarily */
+ WM_cursor_modal_set(win, CURSOR_NONE);
+
+ return 1;
+}
+
+static int walkEnd(bContext *C, WalkInfo *walk)
+{
+ wmWindow *win;
+ RegionView3D *rv3d;
+
+ if (walk->state == WALK_RUNNING)
+ return OPERATOR_RUNNING_MODAL;
+
+#ifdef NDOF_WALK_DEBUG
+ puts("\n-- walk end --");
+#endif
+
+ win = CTX_wm_window(C);
+ rv3d = walk->rv3d;
+
+ WM_event_remove_timer(CTX_wm_manager(C), win, walk->timer);
+
+ ED_region_draw_cb_exit(walk->ar->type, walk->draw_handle_pixel);
+
+ ED_view3d_cameracontrol_release(walk->v3d_camera_control, walk->state == WALK_CANCEL);
+
+ rv3d->rflag &= ~RV3D_NAVIGATING;
+
+ if (walk->ndof)
+ MEM_freeN(walk->ndof);
+
+ /* restore the cursor */
+ WM_cursor_modal_restore(win);
+
+ /* center the mouse */
+ WM_cursor_warp(win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+
+ if (walk->state == WALK_CONFIRM) {
+ MEM_freeN(walk);
+ return OPERATOR_FINISHED;
+ }
+
+ MEM_freeN(walk);
+ return OPERATOR_CANCELLED;
+}
+
+static bool wm_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const wmEvent *event)
+{
+ if (event->type == TIMER && event->customdata == walk->timer) {
+ walk->redraw = true;
+ }
+ else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+
+ walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
+ walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
+
+ copy_v2_v2_int(walk->prev_mval, event->mval);
+
+ if ((walk->center_mval[0] != event->mval[0]) ||
+ (walk->center_mval[1] != event->mval[1]))
+ {
+ walk->redraw = true;
+
+ if (wm_event_is_last_mousemove(event)) {
+ wmWindow *win = CTX_wm_window(C);
+
+#ifdef __APPLE__
+ if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) ||
+ (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2))
+#endif
+ {
+ WM_cursor_warp(win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+ copy_v2_v2_int(walk->prev_mval, walk->center_mval);
+ }
+ }
+ }
+ }
+ else if (event->type == NDOF_MOTION) {
+ /* do these automagically get delivered? yes. */
+ // puts("ndof motion detected in walk mode!");
+ // static const char *tag_name = "3D mouse position";
+
+ wmNDOFMotionData *incoming_ndof = (wmNDOFMotionData *)event->customdata;
+ switch (incoming_ndof->progress) {
+ case P_STARTING:
+ /* start keeping track of 3D mouse position */
+#ifdef NDOF_WALK_DEBUG
+ puts("start keeping track of 3D mouse position");
+#endif
+ /* fall-through */
+ case P_IN_PROGRESS:
+ /* update 3D mouse position */
+#ifdef NDOF_WALK_DEBUG
+ putchar('.'); fflush(stdout);
+#endif
+ if (walk->ndof == NULL) {
+ // walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
+ walk->ndof = MEM_dupallocN(incoming_ndof);
+ // walk->ndof = malloc(sizeof(wmNDOFMotionData));
+ }
+ else {
+ memcpy(walk->ndof, incoming_ndof, sizeof(wmNDOFMotionData));
+ }
+ break;
+ case P_FINISHING:
+ /* stop keeping track of 3D mouse position */
+#ifdef NDOF_WALK_DEBUG
+ puts("stop keeping track of 3D mouse position");
+#endif
+ if (walk->ndof) {
+ MEM_freeN(walk->ndof);
+ // free(walk->ndof);
+ walk->ndof = NULL;
+ }
+
+ /* update the time else the view will jump when 2D mouse/timer resume */
+ walk->time_lastdraw = PIL_check_seconds_timer();
+
+ break;
+ default:
+ break; /* should always be one of the above 3 */
+ }
+ }
+ /* handle modal keymap first */
+ else if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case WALK_MODAL_CANCEL:
+ walk->state = WALK_CANCEL;
+ break;
+ case WALK_MODAL_CONFIRM:
+ walk->state = WALK_CONFIRM;
+ break;
+
+ case WALK_MODAL_ACCELERATE:
+ base_speed *= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
+ break;
+ case WALK_MODAL_DECELERATE:
+ base_speed /= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
+ break;
+
+ /* implement WASD keys */
+ case WALK_MODAL_DIR_FORWARD:
+ walk->active_directions |= WALK_BIT_FORWARD;
+ break;
+ case WALK_MODAL_DIR_BACKWARD:
+ walk->active_directions |= WALK_BIT_BACKWARD;
+ break;
+ case WALK_MODAL_DIR_LEFT:
+ walk->active_directions |= WALK_BIT_LEFT;
+ break;
+ case WALK_MODAL_DIR_RIGHT:
+ walk->active_directions |= WALK_BIT_RIGHT;
+ break;
+ case WALK_MODAL_DIR_UP:
+ walk->active_directions |= WALK_BIT_UP;
+ break;
+ case WALK_MODAL_DIR_DOWN:
+ walk->active_directions |= WALK_BIT_DOWN;
+ break;
+
+ case WALK_MODAL_DIR_FORWARD_STOP:
+ walk->active_directions &= ~WALK_BIT_FORWARD;
+ break;
+ case WALK_MODAL_DIR_BACKWARD_STOP:
+ walk->active_directions &= ~WALK_BIT_BACKWARD;
+ break;
+ case WALK_MODAL_DIR_LEFT_STOP:
+ walk->active_directions &= ~WALK_BIT_LEFT;
+ break;
+ case WALK_MODAL_DIR_RIGHT_STOP:
+ walk->active_directions &= ~WALK_BIT_RIGHT;
+ break;
+ case WALK_MODAL_DIR_UP_STOP:
+ walk->active_directions &= ~WALK_BIT_UP;
+ break;
+ case WALK_MODAL_DIR_DOWN_STOP:
+ walk->active_directions &= ~WALK_BIT_DOWN;
+ break;
+
+ case WALK_MODAL_FAST_ENABLE:
+ walk->is_fast = true;
+ break;
+ case WALK_MODAL_FAST_DISABLE:
+ walk->is_fast = false;
+ break;
+ case WALK_MODAL_SLOW_ENABLE:
+ walk->is_slow = true;
+ break;
+ case WALK_MODAL_SLOW_DISABLE:
+ walk->is_slow = false;
+ break;
+
+#define JUMP_SPEED_MIN 1.0f
+#define JUMP_TIME_MAX 0.2f /* s */
+#define JUMP_SPEED_MAX sqrtf(2.0f * EARTH_GRAVITY * walk->jump_height)
+
+ case WALK_MODAL_JUMP_STOP:
+ if (walk->gravity == WALK_GRAVITY_STATE_JUMP) {
+ float t;
+
+ /* delta time */
+ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);
+
+ /* reduce the veolocity, if JUMP wasn't hold for long enough */
+ t = min_ff(t, JUMP_TIME_MAX);
+ walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX;
+
+ /* when jumping, duration is how long it takes before we start going down */
+ walk->teleport.duration = getVelocityZeroTime(walk->speed_jump);
+
+ /* no more increase of jump speed */
+ walk->gravity = WALK_GRAVITY_STATE_ON;
+ }
+ break;
+ case WALK_MODAL_JUMP:
+ if ((walk->navigation_mode == WALK_MODE_GRAVITY) &&
+ (walk->gravity == WALK_GRAVITY_STATE_OFF) &&
+ (walk->teleport.state == WALK_TELEPORT_STATE_OFF))
+ {
+ /* no need to check for ground,
+ * walk->gravity wouldn't be off
+ * if we were over a hole */
+ walk->gravity = WALK_GRAVITY_STATE_JUMP;
+ walk->speed_jump = JUMP_SPEED_MAX;
+
+ walk->teleport.initial_time = PIL_check_seconds_timer();
+ copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
+
+ /* using previous vec because WASD keys are not called when SPACE is */
+ copy_v2_v2(walk->teleport.direction, walk->dvec_prev);
+
+ /* when jumping, duration is how long it takes before we start going down */
+ walk->teleport.duration = getVelocityZeroTime(walk->speed_jump);
+ }
+
+ break;
+
+ case WALK_MODAL_TELEPORT:
+ {
+ float loc[3], nor[3];
+ float distance;
+ bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance);
+
+ /* in case we are teleporting middle way from a jump */
+ walk->speed_jump = 0.0f;
+
+ if (ret) {
+ WalkTeleport *teleport = &walk->teleport;
+ teleport->state = WALK_TELEPORT_STATE_ON;
+ teleport->initial_time = PIL_check_seconds_timer();
+ teleport->duration = U.walk_navigation.teleport_time;
+
+ teleport->navigation_mode = walk->navigation_mode;
+ walk_navigation_mode_set(walk, WALK_MODE_FREE);
+
+ copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);
+
+ /* stop the camera from a distance (camera height) */
+ normalize_v3(nor);
+ mul_v3_fl(nor, walk->view_height);
+ add_v3_v3(loc, nor);
+
+ sub_v3_v3v3(teleport->direction, loc, teleport->origin);
+ }
+ else {
+ walk->teleport.state = WALK_TELEPORT_STATE_OFF;
+ }
+ break;
+ }
+
+#undef JUMP_SPEED_MAX
+#undef JUMP_TIME_MAX
+#undef JUMP_SPEED_MIN
+
+ case WALK_MODAL_TOGGLE:
+ if (walk->navigation_mode == WALK_MODE_GRAVITY) {
+ walk_navigation_mode_set(walk, WALK_MODE_FREE);
+ }
+ else { /* WALK_MODE_FREE */
+ walk_navigation_mode_set(walk, WALK_MODE_GRAVITY);
+ }
+ break;
+ }
+ }
+}
+
+static void walkMoveCamera(bContext *C, WalkInfo *walk,
+ const bool do_rotate, const bool do_translate)
+{
+ ED_view3d_cameracontrol_update(walk->v3d_camera_control, true, C, do_rotate, do_translate);
+}
+
+static float getFreeFallDistance(const float time)
+{
+ return EARTH_GRAVITY * (time * time) * 0.5f;
+}
+
+static float getVelocityZeroTime(float velocity)
+{
+ return velocity / EARTH_GRAVITY;
+}
+
+static int walkApply(bContext *C, WalkInfo *walk)
+{
+#define WALK_ROTATE_FAC 2.2f /* more is faster */
+#define WALK_TOP_LIMIT DEG2RADF(85.0f)
+#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
+#define WALK_MOVE_SPEED base_speed
+#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
+
+ /* walk mode - Ctrl+Shift+F
+ * a walk loop where the user can move move the view as if they are in a walk game
+ */
+ RegionView3D *rv3d = walk->rv3d;
+ ARegion *ar = walk->ar;
+
+ float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
+ float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */
+
+ /* Camera Uprighting variables */
+ float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */
+
+ int moffset[2]; /* mouse offset from the views center */
+ float tmp_quat[4]; /* used for rotating the view */
+
+#ifdef NDOF_WALK_DEBUG
+ {
+ static unsigned int iteration = 1;
+ printf("walk timer %d\n", iteration++);
+ }
+#endif
+
+ {
+ /* mouse offset from the center */
+ copy_v2_v2_int(moffset, walk->moffset);
+
+ /* apply moffset so we can re-accumulate */
+ walk->moffset[0] = 0;
+ walk->moffset[1] = 0;
+
+ /* revert mouse */
+ if (walk->is_reversed) {
+ moffset[1] = -moffset[1];
+ }
+
+ /* Should we redraw? */
+ if ((walk->active_directions) ||
+ moffset[0] || moffset[1] ||
+ walk->teleport.state == WALK_TELEPORT_STATE_ON ||
+ walk->gravity != WALK_GRAVITY_STATE_OFF)
+ {
+ float dvec_tmp[3];
+
+ /* time how fast it takes for us to redraw,
+ * this is so simple scenes don't walk too fast */
+ double time_current;
+ float time_redraw;
+#ifdef NDOF_WALK_DRAW_TOOMUCH
+ walk->redraw = 1;
+#endif
+ time_current = PIL_check_seconds_timer();
+ time_redraw = (float)(time_current - walk->time_lastdraw);
+
+ walk->time_lastdraw = time_current;
+
+ /* base speed in m/s */
+ walk->speed = WALK_MOVE_SPEED;
+
+ if (walk->is_fast) {
+ walk->speed *= WALK_BOOST_FACTOR;
+ }
+ else if (walk->is_slow) {
+ walk->speed *= 1.0f / WALK_BOOST_FACTOR;
+ }
+
+ copy_m3_m4(mat, rv3d->viewinv);
+
+ {
+ /* rotate about the X axis- look up/down */
+ if (moffset[1]) {
+ float angle;
+ float y;
+
+ /* relative offset */
+ y = (float) moffset[1] / ar->winy;
+
+ /* speed factor */
+ y *= WALK_ROTATE_FAC;
+
+ /* user adjustement factor */
+ y *= walk->mouse_speed;
+
+ /* clamp the angle limits */
+ /* it ranges from 90.0f to -90.0f */
+ angle = -asin(rv3d->viewmat[2][2]);
+
+ if (angle > WALK_TOP_LIMIT && y > 0.0f)
+ y = 0.0f;
+
+ else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f)
+ y = 0.0f;
+
+ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
+ mul_m3_v3(mat, upvec);
+ /* Rotate about the relative up vec */
+ axis_angle_to_quat(tmp_quat, upvec, -y);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+ }
+
+ /* rotate about the Y axis- look left/right */
+ if (moffset[0]) {
+ float x;
+
+ /* if we're upside down invert the moffset */
+ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f);
+ mul_m3_v3(mat, upvec);
+
+ if (upvec[2] < 0.0f)
+ moffset[0] = -moffset[0];
+
+ /* relative offset */
+ x = (float) moffset[0] / ar->winx;
+
+ /* speed factor */
+ x *= WALK_ROTATE_FAC;
+
+ /* user adjustement factor */
+ x *= walk->mouse_speed;
+
+ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
+
+ /* Rotate about the relative up vec */
+ axis_angle_to_quat(tmp_quat, upvec, x);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
+ }
+ }
+
+ /* WASD - 'move' translation code */
+ if ((walk->active_directions) &&
+ (walk->gravity == WALK_GRAVITY_STATE_OFF))
+ {
+
+ short direction;
+ zero_v3(dvec);
+
+ if ((walk->active_directions & WALK_BIT_FORWARD) ||
+ (walk->active_directions & WALK_BIT_BACKWARD))
+ {
+
+ direction = 0;
+
+ if ((walk->active_directions & WALK_BIT_FORWARD))
+ direction += 1;
+
+ if ((walk->active_directions & WALK_BIT_BACKWARD))
+ direction -= 1;
+
+ copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
+ mul_m3_v3(mat, dvec_tmp);
+
+ if (walk->navigation_mode == WALK_MODE_GRAVITY) {
+ dvec_tmp[2] = 0.0f;
+ }
+
+ normalize_v3(dvec_tmp);
+ add_v3_v3(dvec, dvec_tmp);
+
+ }
+
+ if ((walk->active_directions & WALK_BIT_LEFT) ||
+ (walk->active_directions & WALK_BIT_RIGHT))
+ {
+
+ direction = 0;
+
+ if ((walk->active_directions & WALK_BIT_LEFT))
+ direction += 1;
+
+ if ((walk->active_directions & WALK_BIT_RIGHT))
+ direction -= 1;
+
+ dvec_tmp[0] = direction * rv3d->viewinv[0][0];
+ dvec_tmp[1] = direction * rv3d->viewinv[0][1];
+ dvec_tmp[2] = 0.0f;
+
+ normalize_v3(dvec_tmp);
+ add_v3_v3(dvec, dvec_tmp);
+
+ }
+
+ if ((walk->active_directions & WALK_BIT_UP) ||
+ (walk->active_directions & WALK_BIT_DOWN))
+ {
+
+ if (walk->navigation_mode == WALK_MODE_FREE) {
+
+ direction = 0;
+
+ if ((walk->active_directions & WALK_BIT_UP))
+ direction -= 1;
+
+ if ((walk->active_directions & WALK_BIT_DOWN))
+ direction = 1;
+
+ copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
+ add_v3_v3(dvec, dvec_tmp);
+ }
+ }
+
+ /* apply movement */
+ mul_v3_fl(dvec, walk->speed * time_redraw);
+ }
+
+ /* stick to the floor */
+ if (walk->navigation_mode == WALK_MODE_GRAVITY &&
+ ELEM(walk->gravity,
+ WALK_GRAVITY_STATE_OFF,
+ WALK_GRAVITY_STATE_START))
+ {
+
+ bool ret;
+ float ray_distance;
+ float difference = -100.0f;
+ float fall_distance;
+
+ ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);
+
+ if (ret) {
+ difference = walk->view_height - ray_distance;
+ }
+
+ /* the distance we would fall naturally smoothly enough that we
+ can manually drop the object without activating gravity */
+ fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR;
+
+ if (fabsf(difference) < fall_distance) {
+ /* slope/stairs */
+ dvec[2] -= difference;
+
+ /* in case we switched from FREE to GRAVITY too close to the ground */
+ if (walk->gravity == WALK_GRAVITY_STATE_START)
+ walk->gravity = WALK_GRAVITY_STATE_OFF;
+ }
+ else {
+ /* hijack the teleport variables */
+ walk->teleport.initial_time = PIL_check_seconds_timer();
+ walk->gravity = WALK_GRAVITY_STATE_ON;
+ walk->teleport.duration = 0.0f;
+
+ copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
+ copy_v2_v2(walk->teleport.direction, dvec);
+
+ }
+ }
+
+ /* Falling or jumping) */
+ if (ELEM(walk->gravity, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) {
+ float t;
+ float z_old, z_new;
+ bool ret;
+ float ray_distance, difference = -100.0f;
+
+ /* delta time */
+ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);
+
+ /* keep moving if we were moving */
+ copy_v2_v2(dvec, walk->teleport.direction);
+
+ z_old = walk->rv3d->viewinv[3][2];
+ z_new = walk->teleport.origin[2] - getFreeFallDistance(t) * walk->grid;
+
+ /* jump */
+ z_new += t * walk->speed_jump * walk->grid;
+
+ dvec[2] = z_old - z_new;
+
+ /* duration is the jump duration */
+ if (t > walk->teleport.duration) {
+ /* check to see if we are landing */
+ ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);
+
+ if (ret) {
+ difference = walk->view_height - ray_distance;
+ }
+
+ if (ray_distance < walk->view_height) {
+ /* quit falling */
+ dvec[2] -= difference;
+ walk->gravity = WALK_GRAVITY_STATE_OFF;
+ walk->speed_jump = 0.0f;
+ }
+ }
+ }
+
+ /* Teleport */
+ else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) {
+ float t; /* factor */
+ float new_loc[3];
+ float cur_loc[3];
+
+ /* linear interpolation */
+ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);
+ t /= walk->teleport.duration;
+
+ /* clamp so we don't go past our limit */
+ if (t >= 1.0f) {
+ t = 1.0f;
+ walk->teleport.state = WALK_TELEPORT_STATE_OFF;
+ walk_navigation_mode_set(walk, walk->teleport.navigation_mode);
+ }
+
+ mul_v3_v3fl(new_loc, walk->teleport.direction, t);
+ add_v3_v3(new_loc, walk->teleport.origin);
+
+ copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]);
+ sub_v3_v3v3(dvec, cur_loc, new_loc);
+ }
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
+ if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0f;
+ if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0f;
+ if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0f;
+ }
+
+ /* scale the movement to the scene size */
+ mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
+ add_v3_v3(rv3d->ofs, dvec_tmp);
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ const bool do_rotate = (moffset[0] || moffset[1]);
+ const bool do_translate = (walk->speed != 0.0f);
+ walkMoveCamera(C, walk, do_rotate, do_translate);
+ }
+ }
+ else {
+ /* we're not redrawing but we need to update the time else the view will jump */
+ walk->time_lastdraw = PIL_check_seconds_timer();
+ }
+ /* end drawing */
+ copy_v3_v3(walk->dvec_prev, dvec);
+ }
+
+ return OPERATOR_FINISHED;
+#undef WALK_ROTATE_FAC
+#undef WALK_ZUP_CORRECT_FAC
+#undef WALK_ZUP_CORRECT_ACCEL
+#undef WALK_SMOOTH_FAC
+#undef WALK_TOP_LIMIT
+#undef WALK_BOTTOM_LIMIT
+#undef WALK_MOVE_SPEED
+#undef WALK_BOOST_FACTOR
+}
+
+static int walkApply_ndof(bContext *C, WalkInfo *walk)
+{
+ /* shorthand for oft-used variables */
+ wmNDOFMotionData *ndof = walk->ndof;
+ const float dt = ndof->dt;
+ RegionView3D *rv3d = walk->rv3d;
+ const int flag = U.ndof_flag;
+
+#if 0
+ bool do_rotate = (flag & NDOF_SHOULD_ROTATE) && (walk->pan_view == false);
+ bool do_translate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)) != 0;
+#endif
+
+ bool do_rotate = false;
+ bool do_translate = true;
+
+ float view_inv[4];
+ invert_qt_qt(view_inv, rv3d->viewquat);
+
+ rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */
+
+ if (do_translate) {
+ const float forward_sensitivity = 1.0f;
+ const float vertical_sensitivity = 0.4f;
+ const float lateral_sensitivity = 0.6f;
+
+ float speed = 10.0f; /* blender units per second */
+ /* ^^ this is ok for default cube scene, but should scale with.. something */
+
+ float trans[3] = {lateral_sensitivity * ndof->tvec[0],
+ vertical_sensitivity * ndof->tvec[1],
+ forward_sensitivity * ndof->tvec[2]};
+
+ if (walk->is_slow)
+ speed *= 0.2f;
+
+ mul_v3_fl(trans, speed * dt);
+
+ /* transform motion from view to world coordinates */
+ mul_qt_v3(view_inv, trans);
+
+ if (flag & NDOF_FLY_HELICOPTER) {
+ /* replace world z component with device y (yes it makes sense) */
+ trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1];
+ }
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* respect camera position locks */
+ Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
+ if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.0f;
+ if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.0f;
+ if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.0f;
+ }
+
+ if (!is_zero_v3(trans)) {
+ /* move center of view opposite of hand motion (this is camera mode, not object mode) */
+ sub_v3_v3(rv3d->ofs, trans);
+ do_translate = true;
+ }
+ else {
+ do_translate = false;
+ }
+ }
+
+ if (do_rotate) {
+ const float turn_sensitivity = 1.0f;
+
+ float rotation[4];
+ float axis[3];
+ float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis);
+
+ if (fabsf(angle) > 0.0001f) {
+ do_rotate = true;
+
+ if (walk->is_slow)
+ angle *= 0.2f;
+
+ /* transform rotation axis from view to world coordinates */
+ mul_qt_v3(view_inv, axis);
+
+ /* apply rotation to view */
+ axis_angle_to_quat(rotation, axis, angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
+
+ if (flag & NDOF_LOCK_HORIZON) {
+ /* force an upright viewpoint
+ * TODO: make this less... sudden */
+ float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */
+ float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */
+
+ /* find new inverse since viewquat has changed */
+ invert_qt_qt(view_inv, rv3d->viewquat);
+ /* could apply reverse rotation to existing view_inv to save a few cycles */
+
+ /* transform view vectors to world coordinates */
+ mul_qt_v3(view_inv, view_horizon);
+ mul_qt_v3(view_inv, view_direction);
+
+
+ /* find difference between view & world horizons
+ * true horizon lives in world xy plane, so look only at difference in z */
+ angle = -asinf(view_horizon[2]);
+
+#ifdef NDOF_WALK_DEBUG
+ printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle));
+#endif
+
+ /* rotate view so view horizon = world horizon */
+ axis_angle_to_quat(rotation, view_direction, angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
+ }
+
+ rv3d->view = RV3D_VIEW_USER;
+ }
+ else {
+ do_rotate = false;
+ }
+ }
+
+ if (do_translate || do_rotate) {
+ walk->redraw = true;
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ walkMoveCamera(C, walk, do_rotate, do_translate);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+/****** walk operator ******/
+static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ WalkInfo *walk;
+
+ if (rv3d->viewlock)
+ return OPERATOR_CANCELLED;
+
+ walk = MEM_callocN(sizeof(WalkInfo), "NavigationWalkOperation");
+
+ op->customdata = walk;
+
+ if (initWalkInfo(C, walk, op) == false) {
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+
+ walkEvent(C, op, walk, event);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void walk_cancel(bContext *C, wmOperator *op)
+{
+ WalkInfo *walk = op->customdata;
+
+ walk->state = WALK_CANCEL;
+ walkEnd(C, walk);
+ op->customdata = NULL;
+}
+
+static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int exit_code;
+ bool do_draw = false;
+ WalkInfo *walk = op->customdata;
+ RegionView3D *rv3d = walk->rv3d;
+ Object *walk_object = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
+
+ walk->redraw = false;
+
+ walkEvent(C, op, walk, event);
+
+ if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */
+ if (event->type == NDOF_MOTION) {
+ walkApply_ndof(C, walk);
+ }
+ }
+ else if (event->type == TIMER && event->customdata == walk->timer) {
+ walkApply(C, walk);
+ }
+
+ do_draw |= walk->redraw;
+
+ exit_code = walkEnd(C, walk);
+
+ if (exit_code != OPERATOR_RUNNING_MODAL)
+ do_draw = true;
+
+ if (do_draw) {
+ if (rv3d->persp == RV3D_CAMOB) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, walk_object);
+ }
+
+ // puts("redraw!"); // too frequent, commented with NDOF_WALK_DRAW_TOOMUCH for now
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+
+ return exit_code;
+}
+
+void VIEW3D_OT_walk(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Walk Navigation";
+ ot->description = "Interactively walk around the scene";
+ ot->idname = "VIEW3D_OT_walk";
+
+ /* api callbacks */
+ ot->invoke = walk_invoke;
+ ot->cancel = walk_cancel;
+ ot->modal = walk_modal;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING;
+}
+
+#undef EARTH_GRAVITY
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 37d5f313dfb..c2f159356b3 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -374,6 +374,17 @@ typedef struct SolidLight {
float col[4], spec[4], vec[4];
} SolidLight;
+typedef struct WalkNavigation {
+ float mouse_speed; /* speed factor for look around */
+ float walk_speed;
+ float walk_speed_factor;
+ float view_height;
+ float jump_height;
+ float teleport_time; /* duration to use for teleporting */
+ short flag;
+ short pad[3];
+} WalkNavigation;
+
typedef struct UserDef {
/* UserDef has separate do-version handling, and can be read from other files */
int versionfile, subversionfile;
@@ -477,7 +488,7 @@ typedef struct UserDef {
float gpencil_new_layer_col[4]; /* default color for newly created Grease Pencil layers */
short tweak_threshold;
- short pad3;
+ char navigation_mode, pad;
char author[80]; /* author name for file formats supporting it */
@@ -486,6 +497,8 @@ typedef struct UserDef {
float fcu_inactive_alpha; /* opacity of inactive F-Curves in F-Curve Editor */
float pixelsize; /* private, set by GHOST, to multiply DPI with */
+
+ struct WalkNavigation walk_navigation;
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
@@ -552,6 +565,18 @@ typedef enum eViewZoom_Style {
USER_ZOOM_DOLLY = 2
} eViewZoom_Style;
+/* navigation_mode */
+typedef enum eViewNavigation_Method {
+ VIEW_NAVIGATION_WALK = 0,
+ VIEW_NAVIGATION_FLY = 1,
+} eViewNavigation_Method;
+
+/* flag */
+typedef enum eWalkNavigation_Flag {
+ USER_WALK_GRAVITY = (1 << 0),
+ USER_WALK_MOUSE_REVERSE = (1 << 1),
+} eWalkNavigation_Flag;
+
/* uiflag */
typedef enum eUserpref_UI_Flag {
/* flags 0 and 1 were old flags (for autokeying) that aren't used anymore */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 79e3d7acab6..f7909d23525 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -641,6 +641,7 @@ extern StructRNA RNA_UserPreferencesFilePaths;
extern StructRNA RNA_UserPreferencesInput;
extern StructRNA RNA_UserPreferencesSystem;
extern StructRNA RNA_UserPreferencesView;
+extern StructRNA RNA_UserPreferencesWalkNavigation;
extern StructRNA RNA_UserSolidLight;
extern StructRNA RNA_VectorFont;
extern StructRNA RNA_VertexGroup;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index f1881c8beba..2fb1af74173 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -135,6 +135,8 @@ extern EnumPropertyItem gameproperty_type_items[];
extern EnumPropertyItem viewport_shade_items[];
+extern EnumPropertyItem navigation_mode_items[];
+
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
int rna_node_tree_idname_to_enum(const char *idname);
struct bNodeTreeType *rna_node_tree_type_from_enum(int value);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 0e45d6d4aea..a46d90ca8fd 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -72,6 +72,12 @@ static EnumPropertyItem audio_device_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem navigation_mode_items[] = {
+ {VIEW_NAVIGATION_WALK, "WALK", 0, "Walk", "Interactively walk or free navigate around the scene"},
+ {VIEW_NAVIGATION_FLY, "FLY", 0, "Fly", "Use fly dynamics to navigate the scene"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_object_types.h"
@@ -2873,6 +2879,51 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
}
+static void rna_def_userdef_walk_navigation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WalkNavigation", NULL);
+ RNA_def_struct_sdna(srna, "WalkNavigation");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Walk Navigation", "Walk navigation settings");
+
+ prop = RNA_def_property(srna, "mouse_speed", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01f, 10.0f);
+ RNA_def_property_ui_text(prop, "Mouse Sensitivity", "Speed factor for when looking around, high values mean faster mouse movement");
+
+ prop = RNA_def_property(srna, "walk_speed", PROP_FLOAT, PROP_VELOCITY);
+ RNA_def_property_range(prop, 0.01f, 100.f);
+ RNA_def_property_ui_text(prop, "Walk Speed", "Base speed for walking and flying");
+
+ prop = RNA_def_property(srna, "walk_speed_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.01f, 10.f);
+ RNA_def_property_ui_text(prop, "Speed Factor", "Multiplication factor when using the fast or slow modifiers");
+
+ prop = RNA_def_property(srna, "view_height", PROP_FLOAT, PROP_UNIT_LENGTH);
+ RNA_def_property_ui_range(prop, 0.1f, 10.f, 0.1, 2);
+ RNA_def_property_range(prop, 0.f, 1000.f);
+ RNA_def_property_ui_text(prop, "View Height", "View distance from the floor when walking");
+
+ prop = RNA_def_property(srna, "jump_height", PROP_FLOAT, PROP_UNIT_LENGTH);
+ RNA_def_property_ui_range(prop, 0.1f, 10.f, 0.1, 2);
+ RNA_def_property_range(prop, 0.1f, 100.f);
+ RNA_def_property_ui_text(prop, "Jump Height", "Maximum height of a jump");
+
+ prop = RNA_def_property(srna, "teleport_time", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.f, 10.f);
+ RNA_def_property_ui_text(prop, "Teleport Duration", "Interval of time warp when teleporting in navigation mode");
+
+ prop = RNA_def_property(srna, "use_gravity", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_GRAVITY);
+ RNA_def_property_ui_text(prop, "Gravity", "Walks with gravity, or free navigate");
+
+ prop = RNA_def_property(srna, "use_mouse_reverse", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_MOUSE_REVERSE);
+ RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the mouse look");
+}
+
static void rna_def_userdef_view(BlenderRNA *brna)
{
static EnumPropertyItem timecode_styles[] = {
@@ -3793,7 +3844,19 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Continuous Grab",
"Allow moving the mouse outside the view on some manipulations "
"(transform, ui control drag)");
-
+
+ /* View Navigation */
+ prop = RNA_def_property(srna, "navigation_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "navigation_mode");
+ RNA_def_property_enum_items(prop, navigation_mode_items);
+ RNA_def_property_ui_text(prop, "View Navigation", "Which method to use for viewport navigation");
+
+ prop = RNA_def_property(srna, "walk_navigation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "walk_navigation");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "WalkNavigation");
+ RNA_def_property_ui_text(prop, "Walk Navigation", "Settings for walk navigation mode");
+
/* tweak tablet & mouse preset */
prop = RNA_def_property(srna, "drag_threshold", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dragthreshold");
@@ -4128,6 +4191,7 @@ void RNA_def_userdef(BlenderRNA *brna)
rna_def_userdef_dothemes(brna);
rna_def_userdef_solidlight(brna);
+ rna_def_userdef_walk_navigation(brna);
srna = RNA_def_struct(brna, "UserPreferences", NULL);
RNA_def_struct_sdna(srna, "UserDef");