VR: Move actions from keymaps to actionmaps
Among the changes, the VR add-on preferences were removed, meaning that actions can no longer be stored in user preferences. However, in addition to now being saved to blend files, actions can also be imported/exported via python config files. The default config is described in configs/default.py.
This commit is contained in:
parent
0d1b80b5e2
commit
a26b930830
|
@ -20,9 +20,9 @@
|
|||
|
||||
bl_info = {
|
||||
"name": "VR Scene Inspection",
|
||||
"author": "Julian Eisel (Severin), Sebastian Koenig",
|
||||
"version": (0, 9, 0),
|
||||
"blender": (2, 90, 0),
|
||||
"author": "Julian Eisel (Severin), Sebastian Koenig, Peter Kim (muxed-reality)",
|
||||
"version": (0, 10, 0),
|
||||
"blender": (2, 93, 0),
|
||||
"location": "3D View > Sidebar > VR",
|
||||
"description": ("View the viewport with virtual reality glasses "
|
||||
"(head-mounted displays)"),
|
||||
|
@ -33,6 +33,7 @@ bl_info = {
|
|||
"category": "3D View",
|
||||
}
|
||||
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(main)
|
||||
|
@ -41,11 +42,7 @@ else:
|
|||
from . import main, defaults
|
||||
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
CollectionProperty,
|
||||
IntProperty,
|
||||
BoolProperty,
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
main.VIEW3D_PT_vr_session,
|
||||
|
@ -69,8 +66,6 @@ classes = (
|
|||
main.VIEW3D_OT_cursor_to_vr_landmark,
|
||||
main.VIEW3D_OT_update_vr_landmark,
|
||||
|
||||
main.VRAction,
|
||||
main.VRActionSet,
|
||||
main.VIEW3D_UL_vr_action_sets,
|
||||
main.VIEW3D_MT_vr_action_set_menu,
|
||||
main.VIEW3D_UL_vr_actions,
|
||||
|
@ -79,12 +74,13 @@ classes = (
|
|||
main.VIEW3D_OT_vr_action_set_add,
|
||||
main.VIEW3D_OT_vr_action_set_remove,
|
||||
main.VIEW3D_OT_vr_action_set_activate,
|
||||
main.VIEW3D_OT_vr_action_sets_load_from_prefs,
|
||||
main.VIEW3D_OT_vr_action_set_save_to_prefs,
|
||||
main.VIEW3D_OT_vr_action_sets_import,
|
||||
main.VIEW3D_OT_vr_action_sets_export,
|
||||
main.VIEW3D_OT_vr_action_set_copy,
|
||||
main.VIEW3D_OT_vr_action_sets_clear,
|
||||
main.VIEW3D_OT_vr_action_add,
|
||||
main.VIEW3D_OT_vr_action_remove,
|
||||
main.VIEW3D_OT_vr_action_copy,
|
||||
main.VIEW3D_OT_vr_actions_clear,
|
||||
|
||||
main.VIEW3D_GT_vr_camera_cone,
|
||||
|
@ -92,21 +88,6 @@ classes = (
|
|||
main.VIEW3D_GGT_vr_viewer_pose,
|
||||
main.VIEW3D_GGT_vr_controller_poses,
|
||||
main.VIEW3D_GGT_vr_landmarks,
|
||||
|
||||
main.VRPreferences,
|
||||
#main.PREFERENCES_PT_vr_actions,
|
||||
main.PREFERENCES_UL_vr_action_sets,
|
||||
main.PREFERENCES_MT_vr_action_set_menu,
|
||||
main.PREFERENCES_UL_vr_actions,
|
||||
main.PREFERENCES_MT_vr_action_menu,
|
||||
|
||||
main.PREFERENCES_OT_vr_action_set_add,
|
||||
main.PREFERENCES_OT_vr_action_set_remove,
|
||||
main.PREFERENCES_OT_vr_action_set_copy,
|
||||
main.PREFERENCES_OT_vr_action_sets_clear,
|
||||
main.PREFERENCES_OT_vr_action_add,
|
||||
main.PREFERENCES_OT_vr_action_remove,
|
||||
main.PREFERENCES_OT_vr_actions_clear,
|
||||
)
|
||||
|
||||
|
||||
|
@ -118,27 +99,16 @@ def register():
|
|||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.vr_landmarks = CollectionProperty(
|
||||
bpy.types.Scene.vr_landmarks = bpy.props.CollectionProperty(
|
||||
name="Landmark",
|
||||
type=main.VRLandmark,
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_selected = IntProperty(
|
||||
bpy.types.Scene.vr_landmarks_selected = bpy.props.IntProperty(
|
||||
name="Selected Landmark"
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_active = IntProperty(
|
||||
bpy.types.Scene.vr_landmarks_active = bpy.props.IntProperty(
|
||||
update=main.vr_landmark_active_update,
|
||||
)
|
||||
bpy.types.Scene.vr_action_sets = CollectionProperty(
|
||||
name="Action Set",
|
||||
type=main.VRActionSet,
|
||||
)
|
||||
bpy.types.Scene.vr_action_sets_selected = IntProperty(
|
||||
name="Selected Action Set",
|
||||
)
|
||||
bpy.types.Scene.vr_action_sets_active = IntProperty(
|
||||
default=0,
|
||||
update=main.vr_action_set_active_update,
|
||||
)
|
||||
bpy.types.Scene.vr_headset_object = bpy.props.PointerProperty(
|
||||
name="Headset Object",
|
||||
type=bpy.types.Object,
|
||||
|
@ -156,49 +126,32 @@ def register():
|
|||
)
|
||||
# View3DShading is the only per 3D-View struct with custom property
|
||||
# support, so "abusing" that to get a per 3D-View option.
|
||||
bpy.types.View3DShading.vr_show_virtual_camera = BoolProperty(
|
||||
bpy.types.View3DShading.vr_show_virtual_camera = bpy.props.BoolProperty(
|
||||
name="Show VR Camera"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_controllers = BoolProperty(
|
||||
bpy.types.View3DShading.vr_show_controllers = bpy.props.BoolProperty(
|
||||
name="Show VR Controllers"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_landmarks = BoolProperty(
|
||||
bpy.types.View3DShading.vr_show_landmarks = bpy.props.BoolProperty(
|
||||
name="Show Landmarks"
|
||||
)
|
||||
|
||||
bpy.app.handlers.load_post.append(main.vr_ensure_default_landmark)
|
||||
bpy.app.handlers.load_post.append(main.vr_load_action_properties)
|
||||
bpy.app.handlers.load_post.append(defaults.vr_load_default_action_sets)
|
||||
bpy.app.handlers.save_post.append(main.vr_save_action_properties)
|
||||
bpy.app.handlers.load_post.append(defaults.vr_load_default_actionmaps)
|
||||
bpy.app.handlers.xr_session_start_pre.append(main.vr_create_actions)
|
||||
|
||||
# Register add-on key map.
|
||||
kc = bpy.context.window_manager.keyconfigs.addon
|
||||
if kc:
|
||||
kc.keymaps.new(name="XR Session", space_type='EMPTY', region_type='XR')
|
||||
|
||||
|
||||
def unregister():
|
||||
if not bpy.app.build_options.xr_openxr:
|
||||
bpy.utils.unregister_class(main.VIEW3D_PT_vr_info)
|
||||
return
|
||||
|
||||
# Unregister add-on key map.
|
||||
kc = bpy.context.window_manager.keyconfigs.addon
|
||||
if kc:
|
||||
km = kc.keymaps.find("XR Session", space_type='EMPTY', region_type='XR')
|
||||
if km:
|
||||
kc.keymaps.remove(km)
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
del bpy.types.Scene.vr_landmarks
|
||||
del bpy.types.Scene.vr_landmarks_selected
|
||||
del bpy.types.Scene.vr_landmarks_active
|
||||
del bpy.types.Scene.vr_action_sets
|
||||
del bpy.types.Scene.vr_action_sets_selected
|
||||
del bpy.types.Scene.vr_action_sets_active
|
||||
del bpy.types.Scene.vr_headset_object
|
||||
del bpy.types.Scene.vr_controller0_object
|
||||
del bpy.types.Scene.vr_controller1_object
|
||||
|
@ -207,7 +160,5 @@ def unregister():
|
|||
del bpy.types.View3DShading.vr_show_landmarks
|
||||
|
||||
bpy.app.handlers.load_post.remove(main.vr_ensure_default_landmark)
|
||||
bpy.app.handlers.load_post.remove(main.vr_load_action_properties)
|
||||
bpy.app.handlers.load_post.remove(defaults.vr_load_default_action_sets)
|
||||
bpy.app.handlers.save_post.remove(main.vr_save_action_properties)
|
||||
bpy.app.handlers.load_post.remove(defaults.vr_load_default_actionmaps)
|
||||
bpy.app.handlers.xr_session_start_pre.remove(main.vr_create_actions)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
actionconfig_version = (2, 93, 10)
|
||||
actionconfig_data = \
|
||||
[("default_oculus",
|
||||
{"profile": '/interaction_profiles/oculus/touch_controller'},
|
||||
{"items":
|
||||
[("controller_pose", {"type": 'POSE', "user_path0": '/user/hand/left', "component_path0": '/input/grip/pose', "user_path1": '/user/hand/right', "component_path1": '/input/grip/pose', "pose_is_controller": 'True', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(-0.8726646304130554, 0.0, 0.0)'}, None),
|
||||
("raycast_select", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/trigger/value', "user_path1": '/user/hand/right', "component_path1": '/input/trigger/value', "threshold": '0.30000001192092896', "op": 'wm.xr_select_raycast', "op_flag": 'MODAL'}, None),
|
||||
("grab", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/squeeze/value', "user_path1": '/user/hand/right', "component_path1": '/input/squeeze/value', "threshold": '0.30000001192092896', "op": 'wm.xr_grab', "op_flag": 'MODAL'}, None),
|
||||
("undo", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/x/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.undo', "op_flag": 'PRESS'}, None),
|
||||
("redo", {"type": 'BUTTON', "user_path0": '/user/hand/right', "component_path0": '/input/a/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.redo', "op_flag": 'PRESS'}, None),
|
||||
],
|
||||
},
|
||||
),
|
||||
("default_wmr",
|
||||
{"profile": '/interaction_profiles/microsoft/motion_controller'},
|
||||
{"items":
|
||||
[("controller_pose", {"type": 'POSE', "user_path0": '/user/hand/left', "component_path0": '/input/grip/pose', "user_path1": '/user/hand/right', "component_path1": '/input/grip/pose', "pose_is_controller": 'True', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(-0.7853981852531433, 0.0, 0.0)'}, None),
|
||||
("raycast_select", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/trigger/value', "user_path1": '/user/hand/right', "component_path1": '/input/trigger/value', "threshold": '0.30000001192092896', "op": 'wm.xr_select_raycast', "op_flag": 'MODAL'}, None),
|
||||
("grab", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/squeeze/click', "user_path1": '/user/hand/right', "component_path1": '/input/squeeze/click', "threshold": '0.30000001192092896', "op": 'wm.xr_grab', "op_flag": 'MODAL'}, None),
|
||||
("undo", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/menu/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.undo', "op_flag": 'PRESS'}, None),
|
||||
("redo", {"type": 'BUTTON', "user_path0": '/user/hand/right', "component_path0": '/input/menu/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.redo', "op_flag": 'PRESS'}, None),
|
||||
],
|
||||
},
|
||||
),
|
||||
("default_vive",
|
||||
{"profile": '/interaction_profiles/htc/vive_controller'},
|
||||
{"items":
|
||||
[("controller_pose", {"type": 'POSE', "user_path0": '/user/hand/left', "component_path0": '/input/grip/pose', "user_path1": '/user/hand/right', "component_path1": '/input/grip/pose', "pose_is_controller": 'True', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}, None),
|
||||
("raycast_select", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/trigger/value', "user_path1": '/user/hand/right', "component_path1": '/input/trigger/value', "threshold": '0.30000001192092896', "op": 'wm.xr_select_raycast', "op_flag": 'MODAL'}, None),
|
||||
("grab", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/squeeze/click', "user_path1": '/user/hand/right', "component_path1": '/input/squeeze/click', "threshold": '0.30000001192092896', "op": 'wm.xr_grab', "op_flag": 'MODAL'}, None),
|
||||
("undo", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/menu/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.undo', "op_flag": 'PRESS'}, None),
|
||||
("redo", {"type": 'BUTTON', "user_path0": '/user/hand/right', "component_path0": '/input/menu/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.redo', "op_flag": 'PRESS'}, None),
|
||||
],
|
||||
},
|
||||
),
|
||||
("default_index",
|
||||
{"profile": '/interaction_profiles/valve/index_controller'},
|
||||
{"items":
|
||||
[("controller_pose", {"type": 'POSE', "user_path0": '/user/hand/left', "component_path0": '/input/grip/pose', "user_path1": '/user/hand/right', "component_path1": '/input/grip/pose', "pose_is_controller": 'True', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}, None),
|
||||
("raycast_select", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/trigger/value', "user_path1": '/user/hand/right', "component_path1": '/input/trigger/value', "threshold": '0.30000001192092896', "op": 'wm.xr_select_raycast', "op_flag": 'MODAL'}, None),
|
||||
("grab", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/squeeze/value', "user_path1": '/user/hand/right', "component_path1": '/input/squeeze/value', "threshold": '0.30000001192092896', "op": 'wm.xr_grab', "op_flag": 'MODAL'}, None),
|
||||
("undo", {"type": 'BUTTON', "user_path0": '/user/hand/left', "component_path0": '/input/a/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.undo', "op_flag": 'PRESS'}, None),
|
||||
("redo", {"type": 'BUTTON', "user_path0": '/user/hand/right', "component_path0": '/input/a/click', "user_path1": '', "component_path1": '', "threshold": '0.30000001192092896', "op": 'ed.redo', "op_flag": 'PRESS'}, None),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Only add keywords that are supported.
|
||||
from bpy.app import version as blender_version
|
||||
keywords = {}
|
||||
if blender_version >= (2, 93, 0):
|
||||
keywords["actionconfig_version"] = actionconfig_version
|
||||
import os
|
||||
from viewport_vr_preview.io import actionconfig_import_from_data
|
||||
actionconfig_import_from_data(
|
||||
os.path.splitext(os.path.basename(__file__))[0],
|
||||
actionconfig_data,
|
||||
**keywords,
|
||||
)
|
|
@ -18,126 +18,105 @@
|
|||
|
||||
# <pep8 compliant>
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(main)
|
||||
else:
|
||||
from . import main
|
||||
|
||||
import bpy
|
||||
from bpy.app.handlers import persistent
|
||||
import os.path, importlib.util, math
|
||||
import math
|
||||
from enum import Enum
|
||||
from bl_keymap_utils.io import keyconfig_import_from_data_exec
|
||||
|
||||
def vr_defaults_action_set_add(scene, name, profile):
|
||||
bpy.ops.view3d.vr_action_set_add()
|
||||
|
||||
def vr_defaults_actionmap_add(ac, name, profile):
|
||||
am = ac.actionmaps.new(name)
|
||||
if am:
|
||||
am.profile = profile
|
||||
|
||||
return am
|
||||
|
||||
|
||||
def vr_defaults_actionmap_item_add(am,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
threshold,
|
||||
op,
|
||||
op_flag):
|
||||
|
||||
ami = am.actionmap_items.new(name)
|
||||
if ami:
|
||||
ami.type = 'BUTTON'
|
||||
ami.user_path0 = user_path0
|
||||
ami.component_path0 = component_path0
|
||||
ami.user_path1 = user_path1
|
||||
ami.component_path1 = component_path1
|
||||
ami.threshold = threshold
|
||||
ami.op = op
|
||||
ami.op_flag = op_flag
|
||||
|
||||
return ami
|
||||
|
||||
|
||||
def vr_defaults_pose_actionmap_item_add(am,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
is_controller,
|
||||
location,
|
||||
rotation):
|
||||
ami = am.actionmap_items.new(name)
|
||||
if ami:
|
||||
ami.type = 'POSE'
|
||||
ami.user_path0 = user_path0
|
||||
ami.component_path0 = component_path0
|
||||
ami.user_path1 = user_path1
|
||||
ami.component_path1 = component_path1
|
||||
ami.pose_is_controller = is_controller
|
||||
ami.pose_location = location
|
||||
ami.pose_rotation = rotation
|
||||
|
||||
return ami
|
||||
|
||||
|
||||
def vr_defaults_haptic_actionmap_item_add(am,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
duration,
|
||||
frequency,
|
||||
amplitude):
|
||||
ami = am.actionmap_items.new(name)
|
||||
if ami:
|
||||
ami.type = 'HAPTIC'
|
||||
ami.user_path0 = user_path0
|
||||
ami.component_path0 = component_path0
|
||||
ami.user_path1 = user_path1
|
||||
ami.component_path1 = component_path1
|
||||
ami.duration = duration
|
||||
ami.frequency = frequency
|
||||
ami.amplitude = amplitude
|
||||
|
||||
action_set = scene.vr_action_sets[scene.vr_action_sets_selected]
|
||||
if action_set:
|
||||
action_set.name = name
|
||||
action_set.profile = profile
|
||||
|
||||
return action_set
|
||||
return ami
|
||||
|
||||
|
||||
def vr_defaults_action_set_remove(scene, name):
|
||||
action_set_selected_prev = scene.vr_action_sets_selected
|
||||
|
||||
idx = 0
|
||||
for action_set in scene.vr_action_sets:
|
||||
if (action_set.name == name):
|
||||
scene.vr_action_sets_selected = idx
|
||||
|
||||
bpy.ops.view3d.vr_action_set_remove()
|
||||
|
||||
scene.vr_action_sets_selected = action_set_selected_prev
|
||||
return
|
||||
|
||||
idx += 1
|
||||
|
||||
|
||||
def vr_defaults_action_add(action_set,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
threshold,
|
||||
op,
|
||||
op_flag):
|
||||
bpy.ops.view3d.vr_action_add()
|
||||
|
||||
action = action_set.actions[action_set.actions_selected]
|
||||
if action:
|
||||
action.name = name
|
||||
action.type = 'BUTTON'
|
||||
action.user_path0 = user_path0
|
||||
action.component_path0 = component_path0
|
||||
action.user_path1 = user_path1
|
||||
action.component_path1 = component_path1
|
||||
action.threshold = threshold
|
||||
action.op = op
|
||||
action.op_flag = op_flag
|
||||
|
||||
return action
|
||||
|
||||
|
||||
def vr_defaults_pose_action_add(action_set,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
is_controller,
|
||||
location,
|
||||
rotation):
|
||||
bpy.ops.view3d.vr_action_add()
|
||||
|
||||
action = action_set.actions[action_set.actions_selected]
|
||||
if action:
|
||||
action.name = name
|
||||
action.type = 'POSE'
|
||||
action.user_path0 = user_path0
|
||||
action.component_path0 = component_path0
|
||||
action.user_path1 = user_path1
|
||||
action.component_path1 = component_path1
|
||||
action.pose_is_controller = is_controller
|
||||
action.pose_location = location
|
||||
action.pose_rotation = rotation
|
||||
|
||||
return action
|
||||
|
||||
|
||||
def vr_defaults_haptic_action_add(action_set,
|
||||
name,
|
||||
user_path0,
|
||||
component_path0,
|
||||
user_path1,
|
||||
component_path1,
|
||||
duration,
|
||||
frequency,
|
||||
amplitude):
|
||||
bpy.ops.view3d.vr_action_add()
|
||||
|
||||
action = action_set.actions[action_set.actions_selected]
|
||||
if action:
|
||||
action.name = name
|
||||
action.type = 'HAPTIC'
|
||||
action.user_path0 = user_path0
|
||||
action.component_path0 = component_path0
|
||||
action.user_path1 = user_path1
|
||||
action.component_path1 = component_path1
|
||||
action.duration = duration
|
||||
action.frequency = frequency
|
||||
action.amplitude = amplitude
|
||||
|
||||
return action
|
||||
|
||||
|
||||
# Default action sets.
|
||||
class VRDefaultActionSetNames(Enum):
|
||||
# Default actionmaps.
|
||||
class VRDefaultActionmapNames(Enum):
|
||||
OCULUS = "default_oculus"
|
||||
WMR = "default_wmr"
|
||||
VIVE = "default_vive"
|
||||
INDEX = "default_index"
|
||||
|
||||
# Default actions.
|
||||
class VRDefaultActionNames(Enum):
|
||||
# Default actionmap items.
|
||||
class VRDefaultActionmapItemNames(Enum):
|
||||
CONTROLLER_POSE = "controller_pose"
|
||||
RAYCAST_SELECT = "raycast_select"
|
||||
GRAB = "grab"
|
||||
|
@ -145,268 +124,251 @@ class VRDefaultActionNames(Enum):
|
|||
REDO = "redo"
|
||||
|
||||
|
||||
def vr_defaults_load_oculus(scene):
|
||||
action_set = vr_defaults_action_set_add(scene,
|
||||
VRDefaultActionSetNames.OCULUS.value,
|
||||
"/interaction_profiles/oculus/touch_controller")
|
||||
if not action_set:
|
||||
def vr_defaults_create_oculus(ac):
|
||||
am = vr_defaults_actionmap_add(ac,
|
||||
VRDefaultActionmapNames.OCULUS.value,
|
||||
"/interaction_profiles/oculus/touch_controller")
|
||||
if not am:
|
||||
return
|
||||
|
||||
vr_defaults_pose_action_add(action_set,
|
||||
VRDefaultActionNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(math.radians(-50), 0, 0))
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/value",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/value",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/x/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
action_set.actions_selected = 0
|
||||
vr_defaults_pose_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(math.radians(-50), 0, 0))
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/value",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/value",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/x/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
|
||||
def vr_defaults_load_wmr(scene):
|
||||
action_set = vr_defaults_action_set_add(scene,
|
||||
VRDefaultActionSetNames.WMR.value,
|
||||
"/interaction_profiles/microsoft/motion_controller")
|
||||
if not action_set:
|
||||
def vr_defaults_create_wmr(ac):
|
||||
am = vr_defaults_actionmap_add(ac,
|
||||
VRDefaultActionmapNames.WMR.value,
|
||||
"/interaction_profiles/microsoft/motion_controller")
|
||||
if not am:
|
||||
return
|
||||
|
||||
vr_defaults_pose_action_add(action_set,
|
||||
VRDefaultActionNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(math.radians(-45), 0, 0))
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/click",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/click",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
action_set.actions_selected = 0
|
||||
vr_defaults_pose_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(math.radians(-45), 0, 0))
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/click",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/click",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
|
||||
def vr_defaults_load_vive(scene):
|
||||
action_set = vr_defaults_action_set_add(scene,
|
||||
VRDefaultActionSetNames.VIVE.value,
|
||||
"/interaction_profiles/htc/vive_controller")
|
||||
if not action_set:
|
||||
def vr_defaults_create_vive(ac):
|
||||
am = vr_defaults_actionmap_add(ac,
|
||||
VRDefaultActionmapNames.VIVE.value,
|
||||
"/interaction_profiles/htc/vive_controller")
|
||||
if not am:
|
||||
return
|
||||
|
||||
vr_defaults_pose_action_add(action_set,
|
||||
VRDefaultActionNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(0, 0, 0))
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/click",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/click",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
action_set.actions_selected = 0
|
||||
vr_defaults_pose_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(0, 0, 0))
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/click",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/click",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/menu/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
|
||||
def vr_defaults_load_index(scene):
|
||||
action_set = vr_defaults_action_set_add(scene,
|
||||
VRDefaultActionSetNames.INDEX.value,
|
||||
"/interaction_profiles/valve/index_controller")
|
||||
if not action_set:
|
||||
def vr_defaults_create_index(ac):
|
||||
am = vr_defaults_actionmap_add(ac,
|
||||
VRDefaultActionmapNames.INDEX.value,
|
||||
"/interaction_profiles/valve/index_controller")
|
||||
if not am:
|
||||
return
|
||||
|
||||
vr_defaults_pose_action_add(action_set,
|
||||
VRDefaultActionNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(0, 0, 0))
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/value",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/value",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_action_add(action_set,
|
||||
VRDefaultActionNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
action_set.actions_selected = 0
|
||||
|
||||
|
||||
@persistent
|
||||
def vr_load_default_action_sets(context: bpy.context):
|
||||
scene = bpy.context.scene
|
||||
vr_defaults_pose_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.CONTROLLER_POSE.value,
|
||||
"/user/hand/left",
|
||||
"/input/grip/pose",
|
||||
"/user/hand/right",
|
||||
"/input/grip/pose",
|
||||
True,
|
||||
(0, 0, 0),
|
||||
(0, 0, 0))
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.RAYCAST_SELECT.value,
|
||||
"/user/hand/left",
|
||||
"/input/trigger/value",
|
||||
"/user/hand/right",
|
||||
"/input/trigger/value",
|
||||
0.3,
|
||||
"wm.xr_select_raycast",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.GRAB.value,
|
||||
"/user/hand/left",
|
||||
"/input/squeeze/value",
|
||||
"/user/hand/right",
|
||||
"/input/squeeze/value",
|
||||
0.3,
|
||||
"wm.xr_grab",
|
||||
'MODAL')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.UNDO.value,
|
||||
"/user/hand/left",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.undo",
|
||||
'PRESS')
|
||||
vr_defaults_actionmap_item_add(am,
|
||||
VRDefaultActionmapItemNames.REDO.value,
|
||||
"/user/hand/right",
|
||||
"/input/a/click",
|
||||
"",
|
||||
"",
|
||||
0.3,
|
||||
"ed.redo",
|
||||
'PRESS')
|
||||
|
||||
if len(scene.vr_action_sets) > 0:
|
||||
# Don't load defaults for scenes that already contain action sets.
|
||||
return
|
||||
|
||||
# Load default action sets.
|
||||
vr_defaults_load_oculus(scene)
|
||||
vr_defaults_load_wmr(scene)
|
||||
vr_defaults_load_vive(scene)
|
||||
vr_defaults_load_index(scene)
|
||||
|
||||
scene.vr_action_sets_selected = scene.vr_action_sets_active = 0
|
||||
|
||||
# Load operator properties for default action sets.
|
||||
wm = bpy.context.window_manager
|
||||
kc = wm.keyconfigs.addon
|
||||
if not kc:
|
||||
return
|
||||
|
||||
# Import XR Session key map.
|
||||
dirpath = os.path.join(os.path.dirname(os.path.abspath(__file__)), '')
|
||||
filename = os.path.splitext(os.path.basename(__file__))[0] + ".xrkey"
|
||||
filepath = dirpath + filename + ".py"
|
||||
|
||||
if os.path.exists(filepath):
|
||||
spec = importlib.util.spec_from_file_location(filename, filepath)
|
||||
xr_keymap = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(xr_keymap)
|
||||
|
||||
keyconfig_import_from_data_exec(kc, xr_keymap.keyconfig_data, keyconfig_version=xr_keymap.keyconfig_version)
|
||||
|
||||
|
||||
@persistent
|
||||
def vr_unload_default_action_sets(context: bpy.context):
|
||||
scene = bpy.context.scene
|
||||
def vr_load_default_actionmaps(context: bpy.context):
|
||||
context = bpy.context
|
||||
|
||||
for name in VRDefaultActionSetNames:
|
||||
vr_defaults_action_set_remove(scene, name.value)
|
||||
actionconfigs = context.window_manager.xr_session_settings.actionconfigs
|
||||
if not actionconfigs:
|
||||
return
|
||||
ac = actionconfigs.default
|
||||
if not ac:
|
||||
return
|
||||
|
||||
# Set default action config as active.
|
||||
actionconfigs.active = ac
|
||||
|
||||
if len(ac.actionmaps) > 0:
|
||||
# Don't load defaults for scenes that already contain actionmaps.
|
||||
return
|
||||
|
||||
# Set default action config as active.
|
||||
#actionconfigs.active = ac
|
||||
|
||||
# Load default actionmaps.
|
||||
loaded = main.vr_load_actionmaps(context)
|
||||
|
||||
if not loaded:
|
||||
# Create and save default actionmaps.
|
||||
vr_defaults_create_oculus(ac)
|
||||
vr_defaults_create_wmr(ac)
|
||||
vr_defaults_create_vive(ac)
|
||||
vr_defaults_create_index(ac)
|
||||
|
||||
main.vr_save_actionmaps(context, sort=False)
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
keyconfig_version = (2, 93, 5)
|
||||
keyconfig_data = \
|
||||
[("XR Session",
|
||||
{"space_type": 'EMPTY', "region_type": 'XR'},
|
||||
{"items":
|
||||
[("wm.xr_select_raycast",
|
||||
{"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_oculus', "xr_action": 'raycast_select'},
|
||||
{"properties":
|
||||
[("deselect_all", True),
|
||||
],
|
||||
},
|
||||
),
|
||||
("wm.xr_select_raycast",
|
||||
{"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_vive', "xr_action": 'raycast_select'},
|
||||
{"properties":
|
||||
[("deselect_all", True),
|
||||
],
|
||||
},
|
||||
),
|
||||
("wm.xr_grab", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_vive', "xr_action": 'grab'}, None),
|
||||
("wm.xr_grab", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_oculus', "xr_action": 'grab'}, None),
|
||||
("wm.xr_select_raycast",
|
||||
{"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_wmr', "xr_action": 'raycast_select'},
|
||||
{"properties":
|
||||
[("deselect_all", True),
|
||||
],
|
||||
},
|
||||
),
|
||||
("wm.xr_grab", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_wmr', "xr_action": 'grab'}, None),
|
||||
("wm.xr_select_raycast",
|
||||
{"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_index', "xr_action": 'raycast_select'},
|
||||
{"properties":
|
||||
[("deselect_all", True),
|
||||
],
|
||||
},
|
||||
),
|
||||
("wm.xr_grab", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_index', "xr_action": 'grab'}, None),
|
||||
("ed.undo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_vive', "xr_action": 'undo'}, None),
|
||||
("ed.redo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_vive', "xr_action": 'redo'}, None),
|
||||
("ed.undo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_oculus', "xr_action": 'undo'}, None),
|
||||
("ed.redo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_oculus', "xr_action": 'redo'}, None),
|
||||
("ed.undo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_wmr', "xr_action": 'undo'}, None),
|
||||
("ed.redo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_wmr', "xr_action": 'redo'}, None),
|
||||
("ed.undo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_index', "xr_action": 'undo'}, None),
|
||||
("ed.redo", {"type": 'XR_ACTION', "value": 'ANY', "xr_action_set": 'default_index', "xr_action": 'redo'}, None),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Only add keywords that are supported.
|
||||
from bpy.app import version as blender_version
|
||||
keywords = {}
|
||||
if blender_version >= (2, 92, 0):
|
||||
keywords["keyconfig_version"] = keyconfig_version
|
||||
import os
|
||||
from bl_keymap_utils.io import keyconfig_import_from_data
|
||||
keyconfig_import_from_data(
|
||||
os.path.splitext(os.path.basename(__file__))[0],
|
||||
keyconfig_data,
|
||||
**keywords,
|
||||
)
|
|
@ -0,0 +1,307 @@
|
|||
# ##### 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.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Export Functions
|
||||
|
||||
__all__ = (
|
||||
"actionconfig_export_as_data",
|
||||
"actionconfig_import_from_data",
|
||||
"actionconfig_init_from_data",
|
||||
"actionmap_init_from_data",
|
||||
)
|
||||
|
||||
|
||||
def indent(levels):
|
||||
return levels * " "
|
||||
|
||||
|
||||
def round_float_32(f):
|
||||
from struct import pack, unpack
|
||||
return unpack("f", pack("f", f))[0]
|
||||
|
||||
|
||||
def repr_f32(f):
|
||||
f_round = round_float_32(f)
|
||||
f_str = repr(f)
|
||||
f_str_frac = f_str.partition(".")[2]
|
||||
if not f_str_frac:
|
||||
return f_str
|
||||
for i in range(1, len(f_str_frac)):
|
||||
f_test = round(f, i)
|
||||
f_test_round = round_float_32(f_test)
|
||||
if f_test_round == f_round:
|
||||
return "%.*f" % (i, f_test)
|
||||
return f_str
|
||||
|
||||
|
||||
def am_args_as_data(am):
|
||||
s = [
|
||||
f"\"profile\": '{am.profile}'",
|
||||
]
|
||||
|
||||
return "{" + ", ".join(s) + "}"
|
||||
|
||||
|
||||
def am_data_from_args(am, args):
|
||||
am.profile = args["profile"]
|
||||
|
||||
|
||||
def ami_args_as_data(ami):
|
||||
s = [
|
||||
f"\"type\": '{ami.type}'",
|
||||
f"\"user_path0\": '{ami.user_path0}'",
|
||||
f"\"component_path0\": '{ami.component_path0}'",
|
||||
f"\"user_path1\": '{ami.user_path1}'",
|
||||
f"\"component_path1\": '{ami.component_path1}'",
|
||||
]
|
||||
|
||||
if ami.type == 'BUTTON' or ami.type == 'AXIS':
|
||||
s.append(f"\"threshold\": '{ami.threshold}'")
|
||||
s.append(f"\"op\": '{ami.op}'")
|
||||
s.append(f"\"op_flag\": '{ami.op_flag}'")
|
||||
elif ami.type == 'POSE':
|
||||
s.append(f"\"pose_is_controller\": '{ami.pose_is_controller}'")
|
||||
s.append(f"\"pose_location\": '{ami.pose_location.x, ami.pose_location.y, ami.pose_location.z}'")
|
||||
s.append(f"\"pose_rotation\": '{ami.pose_rotation.x, ami.pose_rotation.y, ami.pose_rotation.z}'")
|
||||
elif ami.type == 'HAPTIC':
|
||||
s.append(f"\"haptic_duration\": '{ami.haptic_duration}'")
|
||||
s.append(f"\"haptic_frequency\": '{ami.haptic_frequency}'")
|
||||
s.append(f"\"haptic_amplitude\": '{ami.haptic_amplitude}'")
|
||||
|
||||
|
||||
return "{" + ", ".join(s) + "}"
|
||||
|
||||
|
||||
def ami_data_from_args(ami, args):
|
||||
ami.type = args["type"]
|
||||
ami.user_path0 = args["user_path0"]
|
||||
ami.component_path0 = args["component_path0"]
|
||||
ami.user_path1 = args["user_path1"]
|
||||
ami.component_path1 = args["component_path1"]
|
||||
|
||||
if ami.type == 'BUTTON' or ami.type == 'AXIS':
|
||||
ami.threshold = float(args["threshold"])
|
||||
ami.op = args["op"]
|
||||
ami.op_flag = args["op_flag"]
|
||||
elif ami.type == 'POSE':
|
||||
ami.pose_is_controller = bool(args["pose_is_controller"])
|
||||
l = args["pose_location"].strip(')(').split(', ')
|
||||
ami.pose_location.x = float(l[0])
|
||||
ami.pose_location.y = float(l[1])
|
||||
ami.pose_location.z = float(l[2])
|
||||
l = args["pose_rotation"].strip(')(').split(', ')
|
||||
ami.pose_rotation.x = float(l[0])
|
||||
ami.pose_rotation.y = float(l[1])
|
||||
ami.pose_rotation.z = float(l[2])
|
||||
elif ami.type == 'HAPTIC':
|
||||
ami.haptic_duration = float(args["haptic_duration"])
|
||||
ami.haptic_frequency = float(args["haptic_frequency"])
|
||||
ami.haptic_amplitude = float(args["haptic_amplitude"])
|
||||
|
||||
|
||||
def _ami_properties_to_lines_recursive(level, properties, lines):
|
||||
from bpy.types import OperatorProperties
|
||||
|
||||
def string_value(value):
|
||||
if isinstance(value, (str, bool, int, set)):
|
||||
return repr(value)
|
||||
elif isinstance(value, float):
|
||||
return repr_f32(value)
|
||||
elif getattr(value, '__len__', False):
|
||||
return repr(tuple(value))
|
||||
raise Exception(f"Export action configuration: can't write {value!r}")
|
||||
|
||||
for pname in properties.bl_rna.properties.keys():
|
||||
if pname != "rna_type":
|
||||
value = getattr(properties, pname)
|
||||
if isinstance(value, OperatorProperties):
|
||||
lines_test = []
|
||||
_ami_properties_to_lines_recursive(level + 2, value, lines_test)
|
||||
if lines_test:
|
||||
lines.append(f"(")
|
||||
lines.append(f"\"{pname}\",\n")
|
||||
lines.append(f"{indent(level + 3)}" "[")
|
||||
lines.extend(lines_test)
|
||||
lines.append("],\n")
|
||||
lines.append(f"{indent(level + 3)}" "),\n" f"{indent(level + 2)}")
|
||||
del lines_test
|
||||
elif properties.is_property_set(pname):
|
||||
value = string_value(value)
|
||||
lines.append((f"(\"{pname}\", {value:s}),\n" f"{indent(level + 2)}"))
|
||||
|
||||
|
||||
def _ami_properties_to_lines(level, ami_props, lines):
|
||||
if ami_props is None:
|
||||
return
|
||||
|
||||
lines_test = [f"\"op_properties\":\n" f"{indent(level + 1)}" "["]
|
||||
_ami_properties_to_lines_recursive(level, ami_props, lines_test)
|
||||
if len(lines_test) > 1:
|
||||
lines_test.append("],\n")
|
||||
lines.extend(lines_test)
|
||||
|
||||
|
||||
def _ami_attrs_or_none(level, ami):
|
||||
lines = []
|
||||
_ami_properties_to_lines(level + 1, ami.op_properties, lines)
|
||||
if not lines:
|
||||
return None
|
||||
return "".join(lines)
|
||||
|
||||
|
||||
def actionconfig_export_as_data(ac, filepath, *, all_actionmaps=True, sort=False):
|
||||
export_actionmaps = []
|
||||
|
||||
for am in ac.actionmaps:
|
||||
if all_actionmaps or am.is_user_modified:
|
||||
export_actionmaps.append(am)
|
||||
|
||||
if sort:
|
||||
export_actionmaps.sort(key=lambda k: k.name)
|
||||
|
||||
with open(filepath, "w", encoding="utf-8") as fh:
|
||||
fw = fh.write
|
||||
|
||||
# Use the file version since it includes the sub-version
|
||||
# which we can bump multiple times between releases.
|
||||
from bpy.app import version_file
|
||||
fw(f"actionconfig_version = {version_file!r}\n")
|
||||
del version_file
|
||||
|
||||
fw("actionconfig_data = \\\n[")
|
||||
|
||||
for am in export_actionmaps:
|
||||
fw("(")
|
||||
fw(f"\"{am.name:s}\",\n")
|
||||
fw(f"{indent(2)}")
|
||||
am_args = am_args_as_data(am)
|
||||
fw(am_args)
|
||||
fw(",\n")
|
||||
fw(f"{indent(2)}" "{")
|
||||
fw(f"\"items\":\n")
|
||||
fw(f"{indent(3)}[")
|
||||
for ami in am.actionmap_items:
|
||||
fw(f"(")
|
||||
ami_args = ami_args_as_data(ami)
|
||||
ami_data = _ami_attrs_or_none(4, ami)
|
||||
fw(f"\"{ami.name:s}\"")
|
||||
if ami_data is None:
|
||||
fw(f", ")
|
||||
else:
|
||||
fw(",\n" f"{indent(5)}")
|
||||
|
||||
fw(ami_args)
|
||||
if ami_data is None:
|
||||
fw(", None),\n")
|
||||
else:
|
||||
fw(",\n")
|
||||
fw(f"{indent(5)}" "{")
|
||||
fw(ami_data)
|
||||
fw(f"{indent(6)}")
|
||||
fw("},\n" f"{indent(5)}")
|
||||
fw("),\n")
|
||||
fw(f"{indent(4)}")
|
||||
fw("],\n" f"{indent(3)}")
|
||||
fw("},\n" f"{indent(2)}")
|
||||
fw("),\n" f"{indent(1)}")
|
||||
|
||||
fw("]\n")
|
||||
fw("\n\n")
|
||||
fw("if __name__ == \"__main__\":\n")
|
||||
|
||||
# We could remove this in the future, as loading new action-maps in older Blender versions
|
||||
# makes less and less sense as Blender changes.
|
||||
fw(" # Only add keywords that are supported.\n")
|
||||
fw(" from bpy.app import version as blender_version\n")
|
||||
fw(" keywords = {}\n")
|
||||
fw(" if blender_version >= (2, 93, 0):\n")
|
||||
fw(" keywords[\"actionconfig_version\"] = actionconfig_version\n")
|
||||
|
||||
fw(" import os\n")
|
||||
fw(" from viewport_vr_preview.io import actionconfig_import_from_data\n")
|
||||
fw(" actionconfig_import_from_data(\n")
|
||||
fw(" os.path.splitext(os.path.basename(__file__))[0],\n")
|
||||
fw(" actionconfig_data,\n")
|
||||
fw(" **keywords,\n")
|
||||
fw(" )\n")
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Import Functions
|
||||
|
||||
def _ami_props_setattr(ami_props, attr, value):
|
||||
if type(value) is list:
|
||||
ami_subprop = getattr(ami_props, attr)
|
||||
for subattr, subvalue in value:
|
||||
_ami_props_setattr(ami_subprop, subattr, subvalue)
|
||||
return
|
||||
|
||||
try:
|
||||
setattr(ami_props, attr, value)
|
||||
except AttributeError:
|
||||
print(f"Warning: property '{attr}' not found in actionmap item '{ami_props.__class__.__name__}'")
|
||||
except Exception as ex:
|
||||
print(f"Warning: {ex!r}")
|
||||
|
||||
|
||||
def actionmap_init_from_data(am, am_items):
|
||||
new_fn = getattr(am.actionmap_items, "new")
|
||||
for (ami_name, ami_args, ami_data) in am_items:
|
||||
ami = new_fn(ami_name) #, **ami_args)
|
||||
ami_data_from_args(ami, ami_args)
|
||||
if ami_data is not None:
|
||||
ami_props_data = ami_data.get("op_properties", None)
|
||||
if ami_props_data is not None:
|
||||
ami_props = ami.op_properties
|
||||
assert type(ami_props_data) is list
|
||||
for attr, value in ami_props_data:
|
||||
_ami_props_setattr(ami_props, attr, value)
|
||||
|
||||
|
||||
def actionconfig_init_from_data(ac, actionconfig_data, actionconfig_version):
|
||||
# Load data in the format defined above.
|
||||
#
|
||||
# Runs at load time, keep this fast!
|
||||
if actionconfig_version is not None:
|
||||
from .versioning import actionconfig_update
|
||||
actionconfig_data = actionconfig_update(actionconfig_data, actionconfig_version)
|
||||
|
||||
for (am_name, am_args, am_content) in actionconfig_data:
|
||||
am = ac.actionmaps.new(am_name) #, **am_args)
|
||||
am_data_from_args(am, am_args)
|
||||
am_items = am_content["items"]
|
||||
# Check here instead of inside 'actionmap_init_from_data'
|
||||
# because we want to allow both tuple & list types in that case.
|
||||
#
|
||||
# For full actionmaps, ensure these are always lists to allow for extending them
|
||||
# in a generic way that doesn't have to check for the type each time.
|
||||
assert type(am_items) is list
|
||||
actionmap_init_from_data(am, am_items)
|
||||
|
||||
|
||||
def actionconfig_import_from_data(name, actionconfig_data, *, actionconfig_version=(0, 0, 0)):
|
||||
# Load data in the format defined above.
|
||||
#
|
||||
# Runs at load time, keep this fast!
|
||||
import bpy
|
||||
ac = bpy.context.window_manager.xr_session_settings.actionconfigs.new(name)
|
||||
actionconfig_init_from_data(ac, actionconfig_data, actionconfig_version)
|
||||
return ac
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
# ##### 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.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
# Update Blender version this action-map was written in:
|
||||
#
|
||||
# When the version is ``(0, 0, 0)``, the action-map being loaded didn't contain any versioning information.
|
||||
# This will older than ``(2, 93, 0)``.
|
||||
|
||||
def actionconfig_update(actionconfig_data, actionconfig_version):
|
||||
from bpy.app import version_file as blender_version
|
||||
if actionconfig_version >= blender_version:
|
||||
return actionconfig_data
|
||||
|
||||
## # Version the action-map.
|
||||
## import copy
|
||||
## has_copy = False
|
||||
##
|
||||
## if actionconfig_version <= (2, 93, 0):
|
||||
## # Only copy once.
|
||||
## if not has_copy:
|
||||
## actionconfig_data = copy.deepcopy(actionconfig_data)
|
||||
## has_copy = True
|
||||
##
|
||||
## for _am_name, _am_parms, am_items_data in actionconfig_data:
|
||||
## for (_item_op, item_event, _item_prop) in am_items_data["items"]:
|
||||
## # Apply version updates here.
|
||||
|
||||
return actionconfig_data
|
Loading…
Reference in New Issue