Skip to content

Commit

Permalink
Add glasses scene signals
Browse files Browse the repository at this point in the history
Moved event handling from T5Manager to T5Interface 
Add T5ManagerBase as an interface stub
Refactored the event handling in T5Interface to call out to T5ManagerBase 
T5Manager extends T5ManagerBase now
Adds signals for adding and removing glasses scenes
  • Loading branch information
patrickdown committed Sep 19, 2023
1 parent 06bf594 commit a594715
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 135 deletions.
110 changes: 109 additions & 1 deletion example/addons/tiltfive/T5Interface.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,33 @@ extends Node
## in editor. This will allow the Godot editor to request
## action information from the interface.

enum GameboardType {
LE = TiltFiveXRInterface.LE_GAMEBOARD,
XE = TiltFiveXRInterface.XE_GAMEBOARD,
XE_Raised = TiltFiveXRInterface.XE_RAISED_GAMEBOARD,
Unknown = TiltFiveXRInterface.NO_GAMEBOARD_SET
}

# State of a set of glasses.
class GlassesState:
var available := false
var attempting_to_reserve := false
var reserved := false
var glasses_scene : Node
var gameboard_type := GameboardType.Unknown
func can_attempt_to_reserve():
return available and (not attempting_to_reserve) and (not reserved)


# Dictionary maps glasses_id -> GlassesState
var glasses_dict: Dictionary

var tilt_five_xr_interface: TiltFiveXRInterface

var t5_manager : T5ManagerBase:
set(value):
t5_manager = value

func get_tilt_five_xr_interface() -> TiltFiveXRInterface:
return tilt_five_xr_interface

Expand Down Expand Up @@ -51,11 +76,94 @@ func _enter_tree():
tilt_five_xr_interface.application_version = ProjectSettings.get_setting_with_override("xr/tilt_five/application_version")

XRServer.add_interface(tilt_five_xr_interface)
tilt_five_xr_interface.glasses_event.connect(_on_glasses_event)


func _exit_tree():
if tilt_five_xr_interface:
tilt_five_xr_interface.glasses_event.disconnect(_on_glasses_event)
if tilt_five_xr_interface.is_initialized():
tilt_five_xr_interface.uninitialize()

XRServer.remove_interface(tilt_five_xr_interface)
tilt_five_xr_interface = null

func _ready():
if not (t5_manager or Engine.is_editor_hint()):
push_error("T5Manager is not set in T5Interface")
return
if !tilt_five_xr_interface.is_initialized():
tilt_five_xr_interface.initialize()

func _start_display(glasses_id : StringName, glasses_scene : Node):
var viewport := t5_manager.get_glasses_scene_viewport(glasses_scene)
var xr_origin := t5_manager.get_glasses_scene_origin(glasses_scene)
tilt_five_xr_interface.start_display(glasses_id, viewport, xr_origin)
var t5_camera := t5_manager.get_glasses_scene_camera(glasses_scene)
if t5_camera:
t5_camera.tracker = "/user/%s/head" % glasses_id
for idx in range(4):
var controller = t5_manager.get_glasses_scene_wand(glasses_scene, idx)
if not controller: break
controller.tracker = "/user/%s/wand_%d" % [glasses_id, idx + 1]

func _process_glasses():
for glasses_id in glasses_dict:
var glasses_state = glasses_dict.get(glasses_id) as GlassesState
if glasses_state.can_attempt_to_reserve() and t5_manager.should_use_glasses(glasses_id):
glasses_state.attempting_to_reserve = true
tilt_five_xr_interface.reserve_glasses(glasses_id, t5_manager.get_glasses_display_name(glasses_id))

func _on_glasses_event(glasses_id, event_num):
var glasses_state = glasses_dict.get(glasses_id) as GlassesState
if not glasses_state:
glasses_state = GlassesState.new()
glasses_dict[glasses_id] = glasses_state
match event_num:
TiltFiveXRInterface.E_AVAILABLE:
print_verbose(glasses_id, " E_AVAILABLE")
glasses_state.available = true
_process_glasses()

TiltFiveXRInterface.E_UNAVAILABLE:
print_verbose(glasses_id, " E_UNAVAILABLE")
glasses_state.available = false
if glasses_state.attempting_to_reserve:
glasses_state.attempting_to_reserve = false
_process_glasses()

TiltFiveXRInterface.E_RESERVED:
print_verbose(glasses_id, " E_RESERVED")
glasses_state.reserved = true
glasses_state.attempting_to_reserve = false

var glasses_scene = t5_manager.create_glasses_scene(glasses_id)

# instance our scene
if glasses_scene:
glasses_state.glasses_scene = glasses_scene
_start_display(glasses_id, glasses_scene)

TiltFiveXRInterface.E_DROPPED:
print_verbose(glasses_id, " E_DROPPED")
glasses_state.reserved = false

var glasses_scene = glasses_state.glasses_scene
if glasses_scene:
t5_manager.release_glasses_scene(glasses_scene)
glasses_state.glasses_scene = null
tilt_five_xr_interface.stop_display(glasses_id)

TiltFiveXRInterface.E_TRACKING:
var gbt = tilt_five_xr_interface.get_gameboard_type(glasses_id)
if glasses_state.gameboard_type != gbt:
glasses_state.gameboard_type = gbt
if glasses_state.glasses_scene:
t5_manager.set_glasses_scene_gameboard_type(glasses_state.glasses_scene, glasses_state.gameboard_type)
print_verbose(glasses_id, " E_TRACKING, Gameboard size = ", tilt_five_xr_interface.get_gameboard_extents(gbt))

TiltFiveXRInterface.E_NOT_TRACKING:
print_verbose(glasses_id, " E_NOT_TRACKING")

_:
print_verbose(glasses_id, " - unknown event: ", event_num)
159 changes: 30 additions & 129 deletions example/addons/tiltfive/T5Manager.gd
Original file line number Diff line number Diff line change
@@ -1,149 +1,50 @@
class_name T5Manager extends Node
class_name T5Manager extends T5ManagerBase

## The T5Manager node should be added to your
## main scene and will manage when glasses
## and wands are detected.
##
## This should be persistent.

signal glasses_available(glasses_id : String)
signal glasses_reserved(glasses_id : String)
signal glasses_dropped(glasses_id : String)
signal glasses_scene_was_added(glasses : T5GlassesBase)
signal glasses_scene_will_be_removed(glasses : T5GlassesBase)

const xr_origin_node := ^"Origin"
const xr_camera_node := ^"Origin/Camera"
const wand_node_list := [^"Origin/Wand_1", ^"Origin/Wand_2", ^"Origin/Wand_3", ^"Origin/Wand_4"]
const wand_node_list := [^"Origin/Wand_1", ^"Origin/Wand_2"]

var tilt_five_xr_interface: TiltFiveXRInterface

@export var automatically_start : bool = true
@export var glasses_scene : PackedScene = preload("res://addons/tiltfive/scenes/T5GlassesBase.tscn")

var reserved_glasses: Dictionary

# We'll add our glasses scenes as children of this node
var glasses_node: Node3D

# Called when the manager is loaded and added to our scene
func _enter_tree():
tilt_five_xr_interface = T5Interface.get_tilt_five_xr_interface()

if tilt_five_xr_interface:
tilt_five_xr_interface.glasses_event.connect(on_glasses_event)

# Called when the manager is removed
func _exit_tree():
if tilt_five_xr_interface:
tilt_five_xr_interface.glasses_event.disconnect(on_glasses_event)

tilt_five_xr_interface = null

# Called when our scene is fully setup
func _ready():
# Create a node on our parent under which we create our glasses scenes
func _ready():
glasses_node = Node3D.new()
glasses_node.name = "TiltFiveGlasses"
get_parent().add_child.call_deferred(glasses_node)

if not tilt_five_xr_interface:
return

if automatically_start and !tilt_five_xr_interface.is_initialized():
tilt_five_xr_interface.initialize()

func start_service() -> bool:
if not tilt_five_xr_interface:
return false

return tilt_five_xr_interface.initialize()

func has_reserved_glasses() -> bool:
for glasses in reserved_glasses:
if reserved_glasses[glasses]:
return true
return false

func reserve_glasses(glasses_id : StringName, display_name := "") -> void:
if not reserved_glasses.has(glasses_id):
print_verbose("Warning: Tilt Five glasses id ", glasses_id, " does not exist")
return
if reserved_glasses[glasses_id]:
print_verbose("Warning: Tilt Five glasses ", glasses_id, " already reserved")
return
if display_name.length() == 0:
display_name = ProjectSettings.get_setting_with_override("xr/tilt_five/default_display_name")
tilt_five_xr_interface.reserve_glasses(glasses_id, display_name)

func start_display(glasses_id : StringName, viewport : SubViewport):
var xr_origin = viewport.get_node(xr_origin_node)
tilt_five_xr_interface.start_display(glasses_id, viewport, xr_origin)
var t5_camera := viewport.get_node_or_null(xr_camera_node) as T5Camera3D
if t5_camera:
t5_camera.tracker = "/user/%s/head" % glasses_id
for idx in 4:
var controller = viewport.get_node_or_null(wand_node_list[idx]) as T5Controller3D
if controller:
controller.tracker = "/user/%s/wand_%d" % [glasses_id, idx + 1]

func node_name_from_glasses_id(glasses_id: String) -> String:
return "Glasses_" + glasses_id.replace("-", "_")

func on_glasses_event(glasses_id, event_num):
match event_num:
TiltFiveXRInterface.E_AVAILABLE:
print_verbose(glasses_id, " E_AVAILABLE")
if not reserved_glasses.has(glasses_id):
reserved_glasses[glasses_id] = false

# If we're managing our glasses scene, reserve our glasses
if glasses_scene:
reserve_glasses(glasses_id)

# Let others who are interested know
glasses_available.emit(glasses_id)

TiltFiveXRInterface.E_UNAVAILABLE:
print_verbose(glasses_id, " E_UNAVAILABLE")

# Let others who are interested know
reserved_glasses.erase(glasses_id)

TiltFiveXRInterface.E_RESERVED:
print_verbose(glasses_id, " E_RESERVED")

reserved_glasses[glasses_id] = true

# If we're managing our glasses scene, instance our scene
if glasses_scene:
var gview = glasses_scene.instantiate()
gview.name = node_name_from_glasses_id(glasses_id)
glasses_node.add_child(gview)
start_display(glasses_id, gview)

# Let others who are interested know
glasses_reserved.emit(glasses_id)

TiltFiveXRInterface.E_DROPPED:
print_verbose(glasses_id, " E_DROPPED")

var node_name = node_name_from_glasses_id(glasses_id)
var gview = glasses_node.get_node_or_null(node_name)
if gview:
tilt_five_xr_interface.stop_display(glasses_id)
glasses_node.remove_child(gview)
gview.queue_free()

if reserved_glasses.get(glasses_id, false):
reserved_glasses[glasses_id] = false
glasses_dropped.emit(glasses_id)

TiltFiveXRInterface.E_TRACKING:
var gbt = tilt_five_xr_interface.get_gameboard_type(glasses_id)
print_verbose(glasses_id, " E_TRACKING, Gameboard size = ", tilt_five_xr_interface.get_gameboard_extents(gbt))

TiltFiveXRInterface.E_NOT_TRACKING:
print_verbose(glasses_id, " E_NOT_TRACKING")

_:
print_verbose(glasses_id, " - unknown event: ", event_num)

func create_glasses_scene(glasses_id : String) -> Node:
var gview = glasses_scene.instantiate()
glasses_node.add_child(gview)
glasses_scene_was_added.emit(gview)
return gview

func release_glasses_scene(glasses_scene : Node) -> void:
glasses_scene_will_be_removed.emit(glasses_scene)
glasses_node.remove_child(glasses_scene)
glasses_scene.queue_free()

func get_glasses_scene_viewport(glasses_scene : Node) -> SubViewport:
return glasses_scene as SubViewport

func get_glasses_scene_origin(glasses_scene : Node) -> T5Origin3D:
return glasses_scene.get_node(xr_origin_node)

func get_glasses_scene_camera(glasses_scene : Node) -> Camera3D:
return glasses_scene.get_node(xr_camera_node)

func get_glasses_scene_wand(glasses_scene : Node, wand_num : int) -> T5Controller3D:
if wand_num < wand_node_list.size():
return glasses_scene.get_node_or_null(wand_node_list[wand_num]) as T5Controller3D
return null

55 changes: 55 additions & 0 deletions example/addons/tiltfive/T5ManagerBase.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
class_name T5ManagerBase extends Node

## The T5ManagerBase derived node should be added to your
## These functions must be overridden
##
## create_glasses_scene
## release_glasses_scene
## get_glasses_scene_viewport
## get_glasses_scene_origin
## get_glasses_scene_camera
## get_glasses_scene_wand
##
## The derived node should be persistent.

# Called when the manager is loaded and added to our scene
func _enter_tree():
T5Interface.t5_manager = self

# Called when the manager is removed
func _exit_tree():
T5Interface.t5_manager = null

func should_use_glasses(glasses_id : String) -> bool:
return true

func get_glasses_display_name(glasses_id : String) -> String:
return ProjectSettings.get_setting_with_override("xr/tilt_five/default_display_name")

func create_glasses_scene(glasses_id : String) -> Node:
push_error("create_glasses_scene not implemented in T5ManagerBase derived class")
return null

func release_glasses_scene(glasses_scene : Node) -> void:
push_error("destroy_glasses_scene not implemented in T5ManagerBase derived class")

func get_glasses_scene_viewport(glasses_scene : Node) -> SubViewport:
push_error("get_glasses_scene_viewport not implemented in T5ManagerBase derived class")
return null

func get_glasses_scene_origin(glasses_scene : Node) -> T5Origin3D:
push_error("get_glasses_scene_origin not implemented in T5ManagerBase derived class")
return null

func get_glasses_scene_camera(glasses_scene : Node) -> Camera3D:
push_error("get_glasses_scene_camera not implemented in T5ManagerBase derived class")
return null

func get_glasses_scene_wand(glasses_scene : Node, wand_num : int) -> T5Controller3D:
push_error("get_glasses_scene_wand not implemented in T5ManagerBase derived class")
return null

func set_glasses_scene_gameboard_type(glasses_scene : Node, gameboard_type : T5Interface.GameboardType) -> void:
pass


4 changes: 3 additions & 1 deletion example/addons/tiltfive/scenes/T5GlassesBase.gd
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
extends SubViewport
class_name T5GlassesBase extends SubViewport

@onready var wand = $Origin/Wand_1

var glasses_id : String

func _process(_delta):
if wand:
var wand_pose : XRPose = wand.get_pose()
Expand Down
4 changes: 2 additions & 2 deletions example/addons/tiltfive/scenes/T5GlassesBase.tscn
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[gd_scene load_steps=2 format=3 uid="uid://je0clrdu7o76"]

[ext_resource type="Script" path="res://addons/tiltfive/scenes/T5GlassesBase.gd" id="1_ra3f6"]
[ext_resource type="Script" path="res://addons/tiltfive/scenes/T5GlassesBase.gd" id="1_tymyw"]

[node name="T5GlassesBase" type="SubViewport"]
size = Vector2i(2, 2)
render_target_update_mode = 0
script = ExtResource("1_ra3f6")
script = ExtResource("1_tymyw")

[node name="Origin" type="T5Origin3D" parent="."]

Expand Down
5 changes: 5 additions & 0 deletions example/main.gd
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
extends Node3D

func _on_t5_manager_glasses_scene_was_added(glasses):
print("Scene ", glasses.name, " added")

func _on_t5_manager_glasses_scene_will_be_removed(glasses):
print("Scene ", glasses.name, " removed")
Loading

0 comments on commit a594715

Please sign in to comment.