diff options
Diffstat (limited to 'viewport_vr_preview/gui.py')
-rw-r--r-- | viewport_vr_preview/gui.py | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/viewport_vr_preview/gui.py b/viewport_vr_preview/gui.py new file mode 100644 index 00000000..7cbeddc1 --- /dev/null +++ b/viewport_vr_preview/gui.py @@ -0,0 +1,642 @@ +# ##### 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> + +if "bpy" in locals(): + import importlib + importlib.reload(action_map) + importlib.reload(properties) +else: + from . import action_map, properties + +import bpy +from bpy.types import ( + Menu, + Panel, + UIList, +) + + +### Session. +class VIEW3D_PT_vr_session(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "VR Session" + + def draw(self, context): + layout = self.layout + session_settings = context.window_manager.xr_session_settings + + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + is_session_running = bpy.types.XrSessionState.is_running(context) + + # Using SNAP_FACE because it looks like a stop icon -- I shouldn't + # have commit rights... + toggle_info = ( + ("Start VR Session", 'PLAY') if not is_session_running else ( + "Stop VR Session", 'SNAP_FACE') + ) + layout.operator("wm.xr_session_toggle", + text=toggle_info[0], icon=toggle_info[1]) + + layout.separator() + + layout.prop(session_settings, "use_positional_tracking") + layout.prop(session_settings, "use_absolute_tracking") + + +### View. +class VIEW3D_PT_vr_session_view(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "View" + + def draw(self, context): + layout = self.layout + session_settings = context.window_manager.xr_session_settings + + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + col = layout.column(align=True, heading="Show") + col.prop(session_settings, "show_floor", text="Floor") + col.prop(session_settings, "show_annotation", text="Annotations") + col.prop(session_settings, "show_selection", text="Selection") + col.prop(session_settings, "show_controllers", text="Controllers") + col.prop(session_settings, "show_custom_overlays", text="Custom Overlays") + + col = layout.column(align=True) + col.prop(session_settings, "controller_draw_style", text="Controller Style") + + col = layout.column(align=True) + col.prop(session_settings, "selection_eye", text="Selection Eye") + + col = layout.column(align=True) + col.prop(session_settings, "clip_start", text="Clip Start") + col.prop(session_settings, "clip_end", text="End") + + +### Landmarks. +class VIEW3D_MT_vr_landmark_menu(Menu): + bl_label = "Landmark Controls" + + def draw(self, _context): + layout = self.layout + + layout.operator("view3d.vr_landmark_from_camera") + layout.operator("view3d.update_vr_landmark") + layout.separator() + layout.operator("view3d.cursor_to_vr_landmark") + layout.operator("view3d.camera_to_vr_landmark") + layout.operator("view3d.add_camera_from_vr_landmark") + + +class VIEW3D_UL_vr_landmarks(UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, + _active_propname, index): + landmark = item + landmark_active_idx = context.scene.vr_landmarks_active + + layout.emboss = 'NONE' + + layout.prop(landmark, "name", text="") + + icon = ( + 'RADIOBUT_ON' if (index == landmark_active_idx) else 'RADIOBUT_OFF' + ) + props = layout.operator( + "view3d.vr_landmark_activate", text="", icon=icon) + props.index = index + + +class VIEW3D_PT_vr_landmarks(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "Landmarks" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + scene = context.scene + landmark_selected = properties.VRLandmark.get_selected_landmark(context) + + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + row = layout.row() + + row.template_list("VIEW3D_UL_vr_landmarks", "", scene, "vr_landmarks", + scene, "vr_landmarks_selected", rows=3) + + col = row.column(align=True) + col.operator("view3d.vr_landmark_add", icon='ADD', text="") + col.operator("view3d.vr_landmark_remove", icon='REMOVE', text="") + col.operator("view3d.vr_landmark_from_session", icon='PLUS', text="") + + col.menu("VIEW3D_MT_vr_landmark_menu", icon='DOWNARROW_HLT', text="") + + if landmark_selected: + layout.prop(landmark_selected, "type") + + if landmark_selected.type == 'OBJECT': + layout.prop(landmark_selected, "base_pose_object") + layout.prop(landmark_selected, "base_scale", text="Scale") + elif landmark_selected.type == 'CUSTOM': + layout.prop(landmark_selected, + "base_pose_location", text="Location") + layout.prop(landmark_selected, + "base_pose_angle", text="Angle") + layout.prop(landmark_selected, + "base_scale", text="Scale") + + +### Actions. +def vr_indented_layout(layout, level): + # Same as _indented_layout() from rna_keymap_ui.py. + indentpx = 16 + if level == 0: + level = 0.0001 # Tweak so that a percentage of 0 won't split by half + indent = level * indentpx / bpy.context.region.width + + split = layout.split(factor=indent) + col = split.column() + col = split.column() + return col + + +def vr_draw_ami(ami, layout, level): + # Similar to draw_kmi() from rna_keymap_ui.py. + col = vr_indented_layout(layout, level) + + if ami.op: + col = col.column(align=True) + box = col.box() + else: + box = col.column() + + split = box.split() + + # Header bar. + row = split.row(align=True) + #row.prop(ami, "show_expanded", text="", emboss=False) + + row.label(text="Operator Properties") + row.label(text=ami.op_name) + + # Expanded, additional event settings. + if ami.op: + box = col.box() + + # Operator properties. + box.template_xr_actionmap_item_properties(ami) + + +class VIEW3D_UL_vr_actionmaps(UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, + _active_propname, index): + ac = action_map.vr_actionconfig_active_get(context) + if not ac: + return + + am_active_idx = ac.active_actionmap + am = item + + layout.emboss = 'NONE' + + layout.prop(am, "name", text="") + + icon = ( + 'RADIOBUT_ON' if (index == am_active_idx) else 'RADIOBUT_OFF' + ) + props = layout.operator( + "view3d.vr_actionmap_activate", text="", icon=icon) + props.index = index + + +class VIEW3D_MT_vr_actionmap_menu(Menu): + bl_label = "Action Map Controls" + + def draw(self, _context): + layout = self.layout + + layout.operator("view3d.vr_actionmaps_defaults_load") + layout.operator("view3d.vr_actionmaps_import") + layout.operator("view3d.vr_actionmaps_export") + layout.operator("view3d.vr_actionmap_copy") + layout.operator("view3d.vr_actionmaps_clear") + + +class VIEW3D_UL_vr_actions(UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, + _active_propname, index): + action = item + + layout.emboss = 'NONE' + + layout.prop(action, "name", text="") + + +class VIEW3D_MT_vr_action_menu(Menu): + bl_label = "Action Controls" + + def draw(self, _context): + layout = self.layout + + layout.operator("view3d.vr_action_copy") + layout.operator("view3d.vr_actions_clear") + + +class VIEW3D_UL_vr_actionbindings(UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, + _active_propname, index): + amb = item + + layout.emboss = 'NONE' + + layout.prop(amb, "name", text="") + + +class VIEW3D_MT_vr_actionbinding_menu(Menu): + bl_label = "Action Binding Controls" + + def draw(self, _context): + layout = self.layout + + layout.operator("view3d.vr_actionbinding_copy") + layout.operator("view3d.vr_actionbindings_clear") + + +class VRActionsPanel: + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_options = {'DEFAULT_CLOSED'} + + +class VIEW3D_PT_vr_actions_actionmaps(VRActionsPanel, Panel): + bl_label = "Action Maps" + + def draw(self, context): + ac = action_map.vr_actionconfig_active_get(context) + if not ac: + return + + scene = context.scene + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + row = layout.row() + row.template_list("VIEW3D_UL_vr_actionmaps", "", ac, "actionmaps", + ac, "selected_actionmap", rows=3) + + col = row.column(align=True) + col.operator("view3d.vr_actionmap_add", icon='ADD', text="") + col.operator("view3d.vr_actionmap_remove", icon='REMOVE', text="") + + col.menu("VIEW3D_MT_vr_actionmap_menu", icon='DOWNARROW_HLT', text="") + + am = action_map.vr_actionmap_selected_get(ac) + + if am: + row = layout.row() + col = row.column(align=True) + + col.prop(am, "name", text="Action Map") + + +class VIEW3D_PT_vr_actions_actions(VRActionsPanel, Panel): + bl_label = "Actions" + bl_parent_id = "VIEW3D_PT_vr_actions_actionmaps" + + def draw(self, context): + ac = action_map.vr_actionconfig_active_get(context) + if not ac: + return + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + am = action_map.vr_actionmap_selected_get(ac) + + if am: + col = vr_indented_layout(layout, 1) + row = col.row() + row.template_list("VIEW3D_UL_vr_actions", "", am, "actionmap_items", + am, "selected_item", rows=3) + + col = row.column(align=True) + col.operator("view3d.vr_action_add", icon='ADD', text="") + col.operator("view3d.vr_action_remove", icon='REMOVE', text="") + + col.menu("VIEW3D_MT_vr_action_menu", icon='DOWNARROW_HLT', text="") + + ami = action_map.vr_actionmap_item_selected_get(am) + + if ami: + row = layout.row() + col = row.column(align=True) + + col.prop(ami, "name", text="Action") + col.prop(ami, "type", text="Type") + col.prop(ami, "user_path0", text="User Path 0") + col.prop(ami, "user_path1", text="User Path 1") + + if ami.type == 'FLOAT' or ami.type == 'VECTOR2D': + col.prop(ami, "op", text="Operator") + col.prop(ami, "op_mode", text="Operator Mode") + col.prop(ami, "bimanual", text="Bimanual") + # Properties. + vr_draw_ami(ami, col, 1) + elif ami.type == 'POSE': + col.prop(ami, "pose_is_controller_grip", text="Use for Controller Grips") + col.prop(ami, "pose_is_controller_aim", text="Use for Controller Aims") + + +class VIEW3D_PT_vr_actions_haptics(VRActionsPanel, Panel): + bl_label = "Haptics" + bl_parent_id = "VIEW3D_PT_vr_actions_actions" + + def draw(self, context): + ac = action_map.vr_actionconfig_active_get(context) + if not ac: + return + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + am = action_map.vr_actionmap_selected_get(ac) + + if am: + ami = action_map.vr_actionmap_item_selected_get(am) + + if ami: + row = layout.row() + col = row.column(align=True) + + if ami.type == 'FLOAT' or ami.type == 'VECTOR2D': + col.prop(ami, "haptic_name", text="Haptic Action") + col.prop(ami, "haptic_match_user_paths", text="Match User Paths") + col.prop(ami, "haptic_duration", text="Duration") + col.prop(ami, "haptic_frequency", text="Frequency") + col.prop(ami, "haptic_amplitude", text="Amplitude") + col.prop(ami, "haptic_mode", text="Haptic Mode") + + +class VIEW3D_PT_vr_actions_bindings(VRActionsPanel, Panel): + bl_label = "Bindings" + bl_parent_id = "VIEW3D_PT_vr_actions_actions" + + def draw(self, context): + ac = action_map.vr_actionconfig_active_get(context) + if not ac: + return + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + am = action_map.vr_actionmap_selected_get(ac) + + if am: + ami = action_map.vr_actionmap_item_selected_get(am) + + if ami: + col = vr_indented_layout(layout, 2) + row = col.row() + row.template_list("VIEW3D_UL_vr_actionbindings", "", ami, "bindings", + ami, "selected_binding", rows=3) + + col = row.column(align=True) + col.operator("view3d.vr_actionbinding_add", icon='ADD', text="") + col.operator("view3d.vr_actionbinding_remove", icon='REMOVE', text="") + + col.menu("VIEW3D_MT_vr_actionbinding_menu", icon='DOWNARROW_HLT', text="") + + amb = action_map.vr_actionmap_binding_selected_get(ami) + + if amb: + row = layout.row() + col = row.column(align=True) + + col.prop(amb, "name", text="Binding") + col.prop(amb, "profile", text="Profile") + col.prop(amb, "component_path0", text="Component Path 0") + col.prop(amb, "component_path1", text="Component Path 1") + if ami.type == 'FLOAT' or ami.type == 'VECTOR2D': + col.prop(amb, "threshold", text="Threshold") + if ami.type == 'FLOAT': + col.prop(amb, "axis0_region", text="Axis Region") + else: # ami.type == 'VECTOR2D' + col.prop(amb, "axis0_region", text="Axis 0 Region") + col.prop(amb, "axis1_region", text="Axis 1 Region") + elif ami.type == 'POSE': + col.prop(amb, "pose_location", text="Location Offset") + col.prop(amb, "pose_rotation", text="Rotation Offset") + + +class VIEW3D_PT_vr_actions_extensions(VRActionsPanel, Panel): + bl_label = "Extensions" + bl_parent_id = "VIEW3D_PT_vr_actions_actionmaps" + + def draw(self, context): + scene = context.scene + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + col = layout.column(align=True) + col.prop(scene, "vr_actions_enable_reverb_g2", text="HP Reverb G2") + col.prop(scene, "vr_actions_enable_cosmos", text="HTC Vive Cosmos") + col.prop(scene, "vr_actions_enable_huawei", text="Huawei") + + +### Motion capture. +class VIEW3D_UL_vr_mocap_objects(UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, + _active_propname, index): + scene_mocap_ob = item + + layout.emboss = 'NONE' + + if scene_mocap_ob.object: + layout.prop(scene_mocap_ob.object, "name", text="") + else: + layout.label(icon='X') + + +class VIEW3D_MT_vr_mocap_object_menu(Menu): + bl_label = "Motion Capture Object Controls" + + def draw(self, _context): + layout = self.layout + + layout.operator("view3d.vr_mocap_object_help") + + +class VIEW3D_PT_vr_motion_capture(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "Motion Capture" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + session_settings = context.window_manager.xr_session_settings + scene = context.scene + + col = layout.column(align=True) + col.label(icon='ERROR', text="Note:") + col.label(text="Settings here may have a significant") + col.label(text="performance impact!") + + layout.separator() + + row = layout.row() + row.template_list("VIEW3D_UL_vr_mocap_objects", "", scene, "vr_mocap_objects", + session_settings, "selected_mocap_object", rows=3) + + col = row.column(align=True) + col.operator("view3d.vr_mocap_object_add", icon='ADD', text="") + col.operator("view3d.vr_mocap_object_remove", icon='REMOVE', text="") + + col.menu("VIEW3D_MT_vr_mocap_object_menu", icon='DOWNARROW_HLT', text="") + + mocap_ob = properties.vr_mocap_object_selected_get(session_settings) + scene_mocap_ob = properties.vr_scene_mocap_object_selected_get(scene, session_settings) + + if mocap_ob and scene_mocap_ob: + row = layout.row() + col = row.column(align=True) + + col.prop(scene_mocap_ob, "object", text="Object") + col.prop(mocap_ob, "user_path", text="User Path") + col.prop(mocap_ob, "enable", text="Enable") + col.prop(mocap_ob, "autokey", text="Auto Key") + col.prop(mocap_ob, "location_offset", text="Location Offset") + col.prop(mocap_ob, "rotation_offset", text="Rotation Offset") + + +### Viewport feedback. +class VIEW3D_PT_vr_viewport_feedback(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "Viewport Feedback" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + scene = context.scene + view3d = context.space_data + session_settings = context.window_manager.xr_session_settings + + col = layout.column(align=True) + col.label(icon='ERROR', text="Note:") + col.label(text="Settings here may have a significant") + col.label(text="performance impact!") + + layout.separator() + + layout.prop(view3d.shading, "vr_show_virtual_camera") + layout.prop(view3d.shading, "vr_show_controllers") + layout.prop(view3d.shading, "vr_show_landmarks") + layout.prop(view3d, "mirror_xr_session") + + +### Info. +class VIEW3D_PT_vr_info(bpy.types.Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "VR" + bl_label = "VR Info" + + @classmethod + def poll(cls, context): + return not bpy.app.build_options.xr_openxr + + def draw(self, context): + layout = self.layout + layout.label(icon='ERROR', text="Built without VR/OpenXR features.") + + +classes = ( + VIEW3D_PT_vr_session, + VIEW3D_PT_vr_session_view, + VIEW3D_PT_vr_landmarks, + VIEW3D_PT_vr_actions_actionmaps, + VIEW3D_PT_vr_actions_actions, + VIEW3D_PT_vr_actions_haptics, + VIEW3D_PT_vr_actions_bindings, + VIEW3D_PT_vr_actions_extensions, + VIEW3D_PT_vr_motion_capture, + VIEW3D_PT_vr_viewport_feedback, + + VIEW3D_UL_vr_landmarks, + VIEW3D_MT_vr_landmark_menu, + + VIEW3D_UL_vr_actionmaps, + VIEW3D_MT_vr_actionmap_menu, + VIEW3D_UL_vr_actions, + VIEW3D_MT_vr_action_menu, + VIEW3D_UL_vr_actionbindings, + VIEW3D_MT_vr_actionbinding_menu, + + VIEW3D_UL_vr_mocap_objects, + VIEW3D_MT_vr_mocap_object_menu, +) + + +def register(): + for cls in classes: + bpy.utils.register_class(cls) + + # 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 = bpy.props.BoolProperty( + name="Show VR Camera" + ) + bpy.types.View3DShading.vr_show_controllers = bpy.props.BoolProperty( + name="Show VR Controllers" + ) + bpy.types.View3DShading.vr_show_landmarks = bpy.props.BoolProperty( + name="Show Landmarks" + ) + + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(cls) + + del bpy.types.View3DShading.vr_show_virtual_camera + del bpy.types.View3DShading.vr_show_controllers + del bpy.types.View3DShading.vr_show_landmarks |