1/**************************************************************************/
2/* openxr_interaction_profile.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "openxr_interaction_profile.h"
32
33void OpenXRIPBinding::_bind_methods() {
34 ClassDB::bind_method(D_METHOD("set_action", "action"), &OpenXRIPBinding::set_action);
35 ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
36 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
37
38 ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
39 ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
40 ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
41 ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"), "set_paths", "get_paths");
42
43 ClassDB::bind_method(D_METHOD("has_path", "path"), &OpenXRIPBinding::has_path);
44 ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path);
45 ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path);
46}
47
48Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
49 // This is a helper function to help build our default action sets
50
51 Ref<OpenXRIPBinding> binding;
52 binding.instantiate();
53 binding->set_action(p_action);
54 binding->parse_paths(String(p_paths));
55
56 return binding;
57}
58
59void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) {
60 action = p_action;
61 emit_changed();
62}
63
64Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
65 return action;
66}
67
68int OpenXRIPBinding::get_path_count() const {
69 return paths.size();
70}
71
72void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
73 paths = p_paths;
74 emit_changed();
75}
76
77PackedStringArray OpenXRIPBinding::get_paths() const {
78 return paths;
79}
80
81void OpenXRIPBinding::parse_paths(const String p_paths) {
82 paths = p_paths.split(",", false);
83 emit_changed();
84}
85
86bool OpenXRIPBinding::has_path(const String p_path) const {
87 return paths.has(p_path);
88}
89
90void OpenXRIPBinding::add_path(const String p_path) {
91 if (!paths.has(p_path)) {
92 paths.push_back(p_path);
93 emit_changed();
94 }
95}
96
97void OpenXRIPBinding::remove_path(const String p_path) {
98 if (paths.has(p_path)) {
99 paths.erase(p_path);
100 emit_changed();
101 }
102}
103
104OpenXRIPBinding::~OpenXRIPBinding() {
105 action.unref();
106}
107
108void OpenXRInteractionProfile::_bind_methods() {
109 ClassDB::bind_method(D_METHOD("set_interaction_profile_path", "interaction_profile_path"), &OpenXRInteractionProfile::set_interaction_profile_path);
110 ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path);
111 ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path");
112
113 ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count);
114 ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding);
115 ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings);
116 ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings);
117 ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings");
118}
119
120Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) {
121 Ref<OpenXRInteractionProfile> profile;
122 profile.instantiate();
123 profile->set_interaction_profile_path(String(p_input_profile_path));
124
125 return profile;
126}
127
128void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) {
129 OpenXRInteractionProfileMetadata *pmd = OpenXRInteractionProfileMetadata::get_singleton();
130 ERR_FAIL_NULL(pmd);
131
132 interaction_profile_path = pmd->check_profile_name(p_input_profile_path);
133 emit_changed();
134}
135
136String OpenXRInteractionProfile::get_interaction_profile_path() const {
137 return interaction_profile_path;
138}
139
140int OpenXRInteractionProfile::get_binding_count() const {
141 return bindings.size();
142}
143
144Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
145 ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>());
146
147 return bindings[p_index];
148}
149
150void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
151 // TODO add check here that our bindings don't contain duplicate actions
152
153 bindings = p_bindings;
154 emit_changed();
155}
156
157Array OpenXRInteractionProfile::get_bindings() const {
158 return bindings;
159}
160
161Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const {
162 for (int i = 0; i < bindings.size(); i++) {
163 Ref<OpenXRIPBinding> binding = bindings[i];
164 if (binding->get_action() == p_action) {
165 return binding;
166 }
167 }
168
169 return Ref<OpenXRIPBinding>();
170}
171
172void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
173 ERR_FAIL_COND(p_binding.is_null());
174
175 if (bindings.find(p_binding) == -1) {
176 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");
177
178 bindings.push_back(p_binding);
179 emit_changed();
180 }
181}
182
183void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
184 int idx = bindings.find(p_binding);
185 if (idx != -1) {
186 bindings.remove_at(idx);
187 emit_changed();
188 }
189}
190
191void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
192 // This is a helper function to help build our default action sets
193
194 Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths);
195 add_binding(binding);
196}
197
198void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) {
199 for (int i = bindings.size() - 1; i >= 0; i--) {
200 Ref<OpenXRIPBinding> binding = bindings[i];
201 if (binding->get_action() == p_action) {
202 remove_binding(binding);
203 }
204 }
205}
206
207bool OpenXRInteractionProfile::has_binding_for_action(const Ref<OpenXRAction> p_action) {
208 for (int i = bindings.size() - 1; i >= 0; i--) {
209 Ref<OpenXRIPBinding> binding = bindings[i];
210 if (binding->get_action() == p_action) {
211 return true;
212 }
213 }
214
215 return false;
216}
217
218OpenXRInteractionProfile::~OpenXRInteractionProfile() {
219 bindings.clear();
220}
221