|
| 1 | +extends Node3D |
| 2 | + |
| 3 | +signal focus_lost |
| 4 | +signal focus_gained |
| 5 | +signal pose_recentered |
| 6 | + |
| 7 | +@export var maximum_refresh_rate : int = 90 |
| 8 | + |
| 9 | +var xr_interface : OpenXRInterface |
| 10 | +var xr_is_focussed = false |
| 11 | + |
| 12 | + |
| 13 | +# Called when the node enters the scene tree for the first time. |
| 14 | +func _ready(): |
| 15 | + xr_interface = XRServer.find_interface("OpenXR") |
| 16 | + if xr_interface and xr_interface.is_initialized(): |
| 17 | + print("OpenXR instantiated successfully.") |
| 18 | + var vp : Viewport = get_viewport() |
| 19 | + |
| 20 | + # Enable XR on our viewport |
| 21 | + vp.use_xr = true |
| 22 | + |
| 23 | + # Make sure v-sync is off, v-sync is handled by OpenXR |
| 24 | + DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) |
| 25 | + |
| 26 | + # Connect the OpenXR events |
| 27 | + xr_interface.connect("session_begun", _on_openxr_session_begun) |
| 28 | + xr_interface.connect("session_visible", _on_openxr_visible_state) |
| 29 | + xr_interface.connect("session_focussed", _on_openxr_focused_state) |
| 30 | + xr_interface.connect("session_stopping", _on_openxr_stopping) |
| 31 | + xr_interface.connect("pose_recentered", _on_openxr_pose_recentered) |
| 32 | + else: |
| 33 | + # We couldn't start OpenXR. |
| 34 | + print("OpenXR not instantiated!") |
| 35 | + get_tree().quit() |
| 36 | + |
| 37 | + |
| 38 | +# Handle OpenXR session ready |
| 39 | +func _on_openxr_session_begun() -> void: |
| 40 | + # Get the reported refresh rate |
| 41 | + var current_refresh_rate = xr_interface.get_display_refresh_rate() |
| 42 | + if current_refresh_rate > 0: |
| 43 | + print("OpenXR: Refresh rate reported as ", str(current_refresh_rate)) |
| 44 | + else: |
| 45 | + print("OpenXR: No refresh rate given by XR runtime") |
| 46 | + |
| 47 | + # See if we have a better refresh rate available |
| 48 | + var new_rate = current_refresh_rate |
| 49 | + var available_rates : Array = xr_interface.get_available_display_refresh_rates() |
| 50 | + if available_rates.size() == 0: |
| 51 | + print("OpenXR: Target does not support refresh rate extension") |
| 52 | + elif available_rates.size() == 1: |
| 53 | + # Only one available, so use it |
| 54 | + new_rate = available_rates[0] |
| 55 | + else: |
| 56 | + for rate in available_rates: |
| 57 | + if rate > new_rate and rate <= maximum_refresh_rate: |
| 58 | + new_rate = rate |
| 59 | + |
| 60 | + # Did we find a better rate? |
| 61 | + if current_refresh_rate != new_rate: |
| 62 | + print("OpenXR: Setting refresh rate to ", str(new_rate)) |
| 63 | + xr_interface.set_display_refresh_rate(new_rate) |
| 64 | + current_refresh_rate = new_rate |
| 65 | + |
| 66 | + # Now match our physics rate |
| 67 | + Engine.physics_ticks_per_second = current_refresh_rate |
| 68 | + |
| 69 | + |
| 70 | +# Handle OpenXR visible state |
| 71 | +func _on_openxr_visible_state() -> void: |
| 72 | + # We always pass this state at startup, |
| 73 | + # but the second time we get this it means our player took off their headset |
| 74 | + if xr_is_focussed: |
| 75 | + print("OpenXR lost focus") |
| 76 | + |
| 77 | + xr_is_focussed = false |
| 78 | + |
| 79 | + # pause our game |
| 80 | + process_mode = Node.PROCESS_MODE_DISABLED |
| 81 | + |
| 82 | + emit_signal("focus_lost") |
| 83 | + |
| 84 | + |
| 85 | +# Handle OpenXR focused state |
| 86 | +func _on_openxr_focused_state() -> void: |
| 87 | + print("OpenXR gained focus") |
| 88 | + xr_is_focussed = true |
| 89 | + |
| 90 | + # unpause our game |
| 91 | + process_mode = Node.PROCESS_MODE_INHERIT |
| 92 | + |
| 93 | + emit_signal("focus_gained") |
| 94 | + |
| 95 | +# Handle OpenXR stopping state |
| 96 | +func _on_openxr_stopping() -> void: |
| 97 | + # Our session is being stopped. |
| 98 | + print("OpenXR is stopping") |
| 99 | + |
| 100 | +# Handle OpenXR pose recentered signal |
| 101 | +func _on_openxr_pose_recentered() -> void: |
| 102 | + # User recentered view, we have to react to this by recentering the view. |
| 103 | + # This is game implementation dependent. |
| 104 | + emit_signal("pose_recentered") |
0 commit comments