Skip to content

Commit 3e36f52

Browse files
committed
OpenXR: change bindings to 'flatten' source paths
1 parent 44fa552 commit 3e36f52

File tree

6 files changed

+148
-94
lines changed

6 files changed

+148
-94
lines changed

modules/openxr/action_map/openxr_action_map.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -576,20 +576,15 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p
576576
const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path());
577577

578578
if (profile != nullptr) {
579-
for (int j = 0; j < ip->get_binding_count(); j++) {
580-
Ref<OpenXRIPBinding> binding = ip->get_binding(j);
581-
if (binding->get_action() == p_action) {
582-
PackedStringArray paths = binding->get_paths();
583-
584-
for (int k = 0; k < paths.size(); k++) {
585-
const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(paths[k]);
586-
if (io_path != nullptr) {
587-
String top_path = io_path->top_level_path;
588-
589-
if (!arr.has(top_path)) {
590-
arr.push_back(top_path);
591-
}
592-
}
579+
Vector<Ref<OpenXRIPBinding>> bindings = ip->get_bindings_for_action(p_action);
580+
for (const Ref<OpenXRIPBinding> &binding : bindings) {
581+
String binding_path = binding->get_binding_path();
582+
const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(binding_path);
583+
if (io_path != nullptr) {
584+
String top_path = io_path->top_level_path;
585+
586+
if (!arr.has(top_path)) {
587+
arr.push_back(top_path);
593588
}
594589
}
595590
}

modules/openxr/action_map/openxr_interaction_profile.cpp

Lines changed: 90 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,30 @@ void OpenXRIPBinding::_bind_methods() {
3535
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
3636
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
3737

38-
ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
38+
ClassDB::bind_method(D_METHOD("set_binding_path", "binding_path"), &OpenXRIPBinding::set_binding_path);
39+
ClassDB::bind_method(D_METHOD("get_binding_path"), &OpenXRIPBinding::get_binding_path);
40+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "binding_path"), "set_binding_path", "get_binding_path");
41+
42+
// Deprecated
43+
#ifndef DISABLE_DEPRECATED
3944
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
4045
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
41-
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths");
46+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paths", "get_paths");
4247

48+
ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
4349
ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path);
4450
ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path);
4551
ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path);
52+
#endif // DISABLE_DEPRECATED
4653
}
4754

48-
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
55+
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path) {
4956
// This is a helper function to help build our default action sets
5057

5158
Ref<OpenXRIPBinding> binding;
5259
binding.instantiate();
5360
binding->set_action(p_action);
54-
binding->parse_paths(String(p_paths));
61+
binding->set_binding_path(p_binding_path);
5562

5663
return binding;
5764
}
@@ -65,42 +72,68 @@ Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
6572
return action;
6673
}
6774

68-
int OpenXRIPBinding::get_path_count() const {
69-
return paths.size();
75+
void OpenXRIPBinding::set_binding_path(const String &path) {
76+
binding_path = path;
77+
emit_changed();
7078
}
7179

72-
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
73-
paths = p_paths;
74-
emit_changed();
80+
String OpenXRIPBinding::get_binding_path() const {
81+
return binding_path;
7582
}
7683

77-
PackedStringArray OpenXRIPBinding::get_paths() const {
84+
#ifndef DISABLE_DEPRECATED
85+
86+
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps.
87+
// Fallback logic, this should ONLY be called when loading older action maps.
88+
// We'll parse this momentarily and extract individual bindings.
89+
binding_path = "";
90+
for (const String &path : p_paths) {
91+
if (!binding_path.is_empty()) {
92+
binding_path += ",";
93+
}
94+
binding_path += path;
95+
}
96+
}
97+
98+
PackedStringArray OpenXRIPBinding::get_paths() const { // Deprecated, but needed for converting old action maps.
99+
// Fallback logic, return an array.
100+
// If we just loaded an old action map from disc, this will be a comma separated list of actions.
101+
// Once parsed there should be only one path in our array.
102+
PackedStringArray paths = binding_path.split(",", false);
103+
78104
return paths;
79105
}
80106

81-
void OpenXRIPBinding::parse_paths(const String p_paths) {
82-
paths = p_paths.split(",", false);
83-
emit_changed();
107+
int OpenXRIPBinding::get_path_count() const { // Deprecated.
108+
// Fallback logic, we only have one entry.
109+
return binding_path.is_empty() ? 0 : 1;
84110
}
85111

86-
bool OpenXRIPBinding::has_path(const String p_path) const {
87-
return paths.has(p_path);
112+
bool OpenXRIPBinding::has_path(const String p_path) const { // Deprecated.
113+
// Fallback logic, return true if this is our path.
114+
return binding_path == p_path;
88115
}
89116

90-
void OpenXRIPBinding::add_path(const String p_path) {
91-
if (!paths.has(p_path)) {
92-
paths.push_back(p_path);
117+
void OpenXRIPBinding::add_path(const String p_path) { // Deprecated.
118+
// Fallback logic, only assign first time this is called.
119+
if (binding_path != p_path) {
120+
ERR_FAIL_COND_MSG(!binding_path.is_empty(), "Method add_path has been deprecated. A binding path was already set, create separate binding resources for each path and use set_binding_path instead.");
121+
122+
binding_path = p_path;
93123
emit_changed();
94124
}
95125
}
96126

97-
void OpenXRIPBinding::remove_path(const String p_path) {
98-
if (paths.has(p_path)) {
99-
paths.erase(p_path);
100-
emit_changed();
101-
}
127+
void OpenXRIPBinding::remove_path(const String p_path) { // Deprecated.
128+
ERR_FAIL_COND_MSG(binding_path != p_path, "Method remove_path has been deprecated. Attempt at removing a different binding path, remove the correct binding record from the interaction profile instead.");
129+
130+
// Fallback logic, clear if this is our path.
131+
binding_path = p_path;
132+
emit_changed();
102133
}
103134

135+
#endif // DISABLE_DEPRECATED
136+
104137
OpenXRIPBinding::~OpenXRIPBinding() {
105138
action.unref();
106139
}
@@ -151,32 +184,52 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
151184
}
152185

153186
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
154-
// TODO add check here that our bindings don't contain duplicate actions
187+
bindings.clear();
188+
189+
for (Ref<OpenXRIPBinding> binding : p_bindings) {
190+
String binding_path = binding->get_binding_path();
191+
if (binding_path.find_char(',') >= 0) {
192+
// Convert old binding approach to new...
193+
add_new_binding(binding->get_action(), binding_path);
194+
} else {
195+
add_binding(binding);
196+
}
197+
}
155198

156-
bindings = p_bindings;
157199
emit_changed();
158200
}
159201

160202
Array OpenXRInteractionProfile::get_bindings() const {
161203
return bindings;
162204
}
163205

164-
Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const {
165-
for (int i = 0; i < bindings.size(); i++) {
166-
Ref<OpenXRIPBinding> binding = bindings[i];
167-
if (binding->get_action() == p_action) {
206+
Ref<OpenXRIPBinding> OpenXRInteractionProfile::find_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path) const {
207+
for (Ref<OpenXRIPBinding> binding : bindings) {
208+
if (binding->get_action() == p_action && binding->get_binding_path() == p_binding_path) {
168209
return binding;
169210
}
170211
}
171212

172213
return Ref<OpenXRIPBinding>();
173214
}
174215

216+
Vector<Ref<OpenXRIPBinding>> OpenXRInteractionProfile::get_bindings_for_action(const Ref<OpenXRAction> p_action) const {
217+
Vector<Ref<OpenXRIPBinding>> ret_bindings;
218+
219+
for (Ref<OpenXRIPBinding> binding : bindings) {
220+
if (binding->get_action() == p_action) {
221+
ret_bindings.push_back(binding);
222+
}
223+
}
224+
225+
return ret_bindings;
226+
}
227+
175228
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
176229
ERR_FAIL_COND(p_binding.is_null());
177230

178231
if (!bindings.has(p_binding)) {
179-
ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
232+
ERR_FAIL_COND_MSG(find_binding(p_binding->get_action(), p_binding->get_binding_path()).is_valid(), "There is already a binding for this action and binding path in this interaction profile.");
180233

181234
bindings.push_back(p_binding);
182235
emit_changed();
@@ -191,11 +244,15 @@ void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
191244
}
192245
}
193246

194-
void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
247+
void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const String &p_paths) {
195248
// This is a helper function to help build our default action sets
196249

197-
Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths);
198-
add_binding(binding);
250+
PackedStringArray paths = p_paths.split(",", false);
251+
252+
for (const String &path : paths) {
253+
Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, path);
254+
add_binding(binding);
255+
}
199256
}
200257

201258
void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) {

modules/openxr/action_map/openxr_interaction_profile.h

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,29 @@ class OpenXRIPBinding : public Resource {
4141

4242
private:
4343
Ref<OpenXRAction> action;
44-
PackedStringArray paths;
44+
String binding_path;
4545

4646
protected:
4747
static void _bind_methods();
4848

4949
public:
50-
static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding
50+
static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path); // Helper function for adding a new binding.
5151

52-
void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding
53-
Ref<OpenXRAction> get_action() const; // Get the action for this binding
52+
void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding.
53+
Ref<OpenXRAction> get_action() const; // Get the action for this binding.
5454

55-
int get_path_count() const; // Get the number of io paths
56-
void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource)
57-
PackedStringArray get_paths() const; // Get our paths (for saving to resource)
55+
void set_binding_path(const String &path);
56+
String get_binding_path() const;
5857

59-
void parse_paths(const String p_paths); // Parse a comma separated string of io paths.
60-
61-
bool has_path(const String p_path) const; // Has this io path
62-
void add_path(const String p_path); // Add an io path
63-
void remove_path(const String p_path); // Remove an io path
58+
// Deprecated.
59+
#ifndef DISABLE_DEPRECATED
60+
void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps.
61+
PackedStringArray get_paths() const; // Get our paths (for saving to resource), needed for converted old action maps.
62+
int get_path_count() const; // Get the number of io paths.
63+
bool has_path(const String p_path) const; // Has this io path.
64+
void add_path(const String p_path); // Add an io path.
65+
void remove_path(const String p_path); // Remove an io path.
66+
#endif // DISABLE_DEPRECATED
6467

6568
// TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path
6669

@@ -88,11 +91,12 @@ class OpenXRInteractionProfile : public Resource {
8891
void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource)
8992
Array get_bindings() const; // Get the bindings (for saving to a resource)
9093

91-
Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action
94+
Ref<OpenXRIPBinding> find_binding(const Ref<OpenXRAction> p_action, const String &p_binding_path) const; // Get our binding record
95+
Vector<Ref<OpenXRIPBinding>> get_bindings_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action
9296
void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object
9397
void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object
9498

95-
void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile
99+
void add_new_binding(const Ref<OpenXRAction> p_action, const String &p_paths); // Create a new binding for this profile
96100
void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action
97101
bool has_binding_for_action(const Ref<OpenXRAction> p_action); // Returns true if we have a binding for this action
98102

modules/openxr/doc_classes/OpenXRIPBinding.xml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,32 @@
44
Defines a binding between an [OpenXRAction] and an XR input or output.
55
</brief_description>
66
<description>
7-
This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
7+
This binding resource binds an [OpenXRAction] to an input or output. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger". This would require two binding entries.
88
</description>
99
<tutorials>
1010
</tutorials>
1111
<methods>
12-
<method name="add_path">
12+
<method name="add_path" deprecated="Binding is for a single path.">
1313
<return type="void" />
1414
<param index="0" name="path" type="String" />
1515
<description>
1616
Add an input/output path to this binding.
1717
</description>
1818
</method>
19-
<method name="get_path_count" qualifiers="const">
19+
<method name="get_path_count" qualifiers="const" deprecated="Binding is for a single path.">
2020
<return type="int" />
2121
<description>
2222
Get the number of input/output paths in this binding.
2323
</description>
2424
</method>
25-
<method name="has_path" qualifiers="const">
25+
<method name="has_path" qualifiers="const" deprecated="Binding is for a single path.">
2626
<return type="bool" />
2727
<param index="0" name="path" type="String" />
2828
<description>
2929
Returns [code]true[/code] if this input/output path is part of this binding.
3030
</description>
3131
</method>
32-
<method name="remove_path">
32+
<method name="remove_path" deprecated="Binding is for a single path.">
3333
<return type="void" />
3434
<param index="0" name="path" type="String" />
3535
<description>
@@ -39,9 +39,13 @@
3939
</methods>
4040
<members>
4141
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
42-
[OpenXRAction] that is bound to these paths.
42+
[OpenXRAction] that is bound to [member binding_path].
4343
</member>
44-
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()">
44+
<member name="binding_path" type="String" setter="set_binding_path" getter="get_binding_path" default="&quot;&quot;">
45+
Binding path that defines the input or output bound to [member action].
46+
[b]Note:[/b] Binding paths are suggestions, an XR runtime may choose to bind the action to a different input or output emulating this input or output.
47+
</member>
48+
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" deprecated="Use [member binding_path] instead.">
4549
Paths that define the inputs or outputs bound on the device.
4650
</member>
4751
</members>

0 commit comments

Comments
 (0)