1 /**
2 AR/VR interface using WebXR.
3 
4 Copyright:
5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.  
6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)  
7 Copyright (c) 2017-2018 Godot-D contributors  
8 
9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
10 
11 
12 */
13 module godot.webxrinterface;
14 import std.meta : AliasSeq, staticIndexOf;
15 import std.traits : Unqual;
16 import godot.d.traits;
17 import godot.core;
18 import godot.c;
19 import godot.d.bind;
20 import godot.d.reference;
21 import godot.globalenums;
22 import godot.object;
23 import godot.arvrinterface;
24 import godot.reference;
25 import godot.arvrpositionaltracker;
26 /**
27 AR/VR interface using WebXR.
28 
29 WebXR is an open standard that allows creating VR and AR applications that run in the web browser.
30 As such, this interface is only available when running in an HTML5 export.
31 WebXR supports a wide range of devices, from the very capable (like Valve Index, HTC Vive, Oculus Rift and Quest) down to the much less capable (like Google Cardboard, Oculus Go, GearVR, or plain smartphones).
32 Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that $(D WebXRInterface) is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes $(D WebXRInterface) quite a bit more complicated to initialize than other AR/VR interfaces.
33 Here's the minimum code required to start an immersive VR session:
34 
35 
36 extends Spatial
37 
38 var webxr_interface
39 var vr_supported = false
40 
41 func _ready():
42     # We assume this node has a button as a child.
43     # This button is for the user to consent to entering immersive VR mode.
44     $Button.connect("pressed", self, "_on_Button_pressed")
45 
46     webxr_interface = ARVRServer.find_interface("WebXR")
47     if webxr_interface:
48         # WebXR uses a lot of asynchronous callbacks, so we connect to various
49         # signals in order to receive them.
50         webxr_interface.connect("session_supported", self, "_webxr_session_supported")
51         webxr_interface.connect("session_started", self, "_webxr_session_started")
52         webxr_interface.connect("session_ended", self, "_webxr_session_ended")
53         webxr_interface.connect("session_failed", self, "_webxr_session_failed")
54 
55         # This returns immediately - our _webxr_session_supported() method
56         # (which we connected to the "session_supported" signal above) will
57         # be called sometime later to let us know if it's supported or not.
58         webxr_interface.is_session_supported("immersive-vr")
59 
60 func _webxr_session_supported(session_mode, supported):
61     if session_mode == 'immersive-vr':
62         vr_supported = supported
63 
64 func _on_Button_pressed():
65     if not vr_supported:
66         OS.alert("Your browser doesn't support VR")
67         return
68 
69     # We want an immersive VR session, as opposed to AR ('immersive-ar') or a
70     # simple 3DoF viewer ('viewer').
71     webxr_interface.session_mode = 'immersive-vr'
72     # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting
73     # experience (it puts you 1.6m above the ground if you have 3DoF headset),
74     # whereas as 'local' puts you down at the ARVROrigin.
75     # This list means it'll first try to request 'bounded-floor', then
76     # fallback on 'local-floor' and ultimately 'local', if nothing else is
77     # supported.
78     webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local'
79     # In order to use 'local-floor' or 'bounded-floor' we must also
80     # mark the features as required or optional.
81     webxr_interface.required_features = 'local-floor'
82     webxr_interface.optional_features = 'bounded-floor'
83 
84     # This will return false if we're unable to even request the session,
85     # however, it can still fail asynchronously later in the process, so we
86     # only know if it's really succeeded or failed when our
87     # _webxr_session_started() or _webxr_session_failed() methods are called.
88     if not webxr_interface.initialize():
89         OS.alert("Failed to initialize")
90         return
91 
92 func _webxr_session_started():
93     $Button.visible = false
94     # This tells Godot to start rendering to the headset.
95     get_viewport().arvr = true
96     # This will be the reference space type you ultimately got, out of the
97     # types that you requested above. This is useful if you want the game to
98     # work a little differently in 'bounded-floor' versus 'local-floor'.
99     print ("Reference space type: " + webxr_interface.reference_space_type)
100 
101 func _webxr_session_ended():
102     $Button.visible = true
103     # If the user exits immersive mode, then we tell Godot to render to the web
104     # page again.
105     get_viewport().arvr = false
106 
107 func _webxr_session_failed(message):
108     OS.alert("Failed to initialize: " + message)
109 
110 
111 There are several ways to handle "controller" input:
112 - Using $(D ARVRController) nodes and their $(D ARVRController.buttonPressed) and $(D ARVRController.buttonRelease) signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by $(D url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping)Section 3.3 of the WebXR Gamepads Module$(D /url).
113 - Using $(D Node._unhandledInput) and $(D InputEventJoypadButton) or $(D InputEventJoypadMotion). This works the same as normal joypads, except the $(D InputEvent.device) starts at 100, so the left controller is 100 and the right controller is 101, and the button codes are also defined by $(D url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping)Section 3.3 of the WebXR Gamepads Module$(D /url).
114 - Using the $(D select), $(D squeeze) and related signals. This method will work for both advanced VR controllers, and non-traditional "controllers" like a tap on the screen, a spoken voice command or a button press on the device itself. The `controller_id` passed to these signals is the same id as used in $(D ARVRController.controllerId).
115 You can use one or all of these methods to allow your game or app to support a wider or narrower set of devices and input methods, or to allow more advanced interations with more advanced devices.
116 */
117 @GodotBaseClass struct WebXRInterface
118 {
119 	package(godot) enum string _GODOT_internal_name = "WebXRInterface";
120 public:
121 @nogc nothrow:
122 	union { /** */ godot_object _godot_object; /** */ ARVRInterface _GODOT_base; }
123 	alias _GODOT_base this;
124 	alias BaseClasses = AliasSeq!(typeof(_GODOT_base), typeof(_GODOT_base).BaseClasses);
125 	package(godot) __gshared bool _classBindingInitialized = false;
126 	package(godot) static struct GDNativeClassBinding
127 	{
128 		__gshared:
129 		@GodotName("get_bounds_geometry") GodotMethod!(PoolVector3Array) getBoundsGeometry;
130 		@GodotName("get_controller") GodotMethod!(ARVRPositionalTracker, long) getController;
131 		@GodotName("get_optional_features") GodotMethod!(String) getOptionalFeatures;
132 		@GodotName("get_reference_space_type") GodotMethod!(String) getReferenceSpaceType;
133 		@GodotName("get_requested_reference_space_types") GodotMethod!(String) getRequestedReferenceSpaceTypes;
134 		@GodotName("get_required_features") GodotMethod!(String) getRequiredFeatures;
135 		@GodotName("get_session_mode") GodotMethod!(String) getSessionMode;
136 		@GodotName("get_visibility_state") GodotMethod!(String) getVisibilityState;
137 		@GodotName("is_session_supported") GodotMethod!(void, String) isSessionSupported;
138 		@GodotName("set_optional_features") GodotMethod!(void, String) setOptionalFeatures;
139 		@GodotName("set_requested_reference_space_types") GodotMethod!(void, String) setRequestedReferenceSpaceTypes;
140 		@GodotName("set_required_features") GodotMethod!(void, String) setRequiredFeatures;
141 		@GodotName("set_session_mode") GodotMethod!(void, String) setSessionMode;
142 	}
143 	/// 
144 	pragma(inline, true) bool opEquals(in WebXRInterface other) const
145 	{ return _godot_object.ptr is other._godot_object.ptr; }
146 	/// 
147 	pragma(inline, true) typeof(null) opAssign(typeof(null) n)
148 	{ _godot_object.ptr = n; return null; }
149 	/// 
150 	pragma(inline, true) bool opEquals(typeof(null) n) const
151 	{ return _godot_object.ptr is n; }
152 	/// 
153 	size_t toHash() const @trusted { return cast(size_t)_godot_object.ptr; }
154 	mixin baseCasts;
155 	/// Construct a new instance of WebXRInterface.
156 	/// Note: use `memnew!WebXRInterface` instead.
157 	static WebXRInterface _new()
158 	{
159 		static godot_class_constructor constructor;
160 		if(constructor is null) constructor = _godot_api.godot_get_class_constructor("WebXRInterface");
161 		if(constructor is null) return typeof(this).init;
162 		return cast(WebXRInterface)(constructor());
163 	}
164 	@disable new(size_t s);
165 	/**
166 	
167 	*/
168 	PoolVector3Array getBoundsGeometry() const
169 	{
170 		checkClassBinding!(typeof(this))();
171 		return ptrcall!(PoolVector3Array)(GDNativeClassBinding.getBoundsGeometry, _godot_object);
172 	}
173 	/**
174 	Gets an $(D ARVRPositionalTracker) for the given `controller_id`.
175 	In the context of WebXR, a "controller" can be an advanced VR controller like the Oculus Touch or Index controllers, or even a tap on the screen, a spoken voice command or a button press on the device itself. When a non-traditional controller is used, interpret the position and orientation of the $(D ARVRPositionalTracker) as a ray pointing at the object the user wishes to interact with.
176 	Use this method to get information about the controller that triggered one of these signals:
177 	- $(D selectstart)
178 	- $(D select)
179 	- $(D selectend)
180 	- $(D squeezestart)
181 	- $(D squeeze)
182 	- $(D squeezestart)
183 	*/
184 	ARVRPositionalTracker getController(in long controller_id) const
185 	{
186 		checkClassBinding!(typeof(this))();
187 		return ptrcall!(ARVRPositionalTracker)(GDNativeClassBinding.getController, _godot_object, controller_id);
188 	}
189 	/**
190 	
191 	*/
192 	String getOptionalFeatures() const
193 	{
194 		checkClassBinding!(typeof(this))();
195 		return ptrcall!(String)(GDNativeClassBinding.getOptionalFeatures, _godot_object);
196 	}
197 	/**
198 	
199 	*/
200 	String getReferenceSpaceType() const
201 	{
202 		checkClassBinding!(typeof(this))();
203 		return ptrcall!(String)(GDNativeClassBinding.getReferenceSpaceType, _godot_object);
204 	}
205 	/**
206 	
207 	*/
208 	String getRequestedReferenceSpaceTypes() const
209 	{
210 		checkClassBinding!(typeof(this))();
211 		return ptrcall!(String)(GDNativeClassBinding.getRequestedReferenceSpaceTypes, _godot_object);
212 	}
213 	/**
214 	
215 	*/
216 	String getRequiredFeatures() const
217 	{
218 		checkClassBinding!(typeof(this))();
219 		return ptrcall!(String)(GDNativeClassBinding.getRequiredFeatures, _godot_object);
220 	}
221 	/**
222 	
223 	*/
224 	String getSessionMode() const
225 	{
226 		checkClassBinding!(typeof(this))();
227 		return ptrcall!(String)(GDNativeClassBinding.getSessionMode, _godot_object);
228 	}
229 	/**
230 	
231 	*/
232 	String getVisibilityState() const
233 	{
234 		checkClassBinding!(typeof(this))();
235 		return ptrcall!(String)(GDNativeClassBinding.getVisibilityState, _godot_object);
236 	}
237 	/**
238 	Checks if the given `session_mode` is supported by the user's browser.
239 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode)WebXR's XRSessionMode$(D /url), including: `"immersive-vr"`, `"immersive-ar"`, and `"inline"`.
240 	This method returns nothing, instead it emits the $(D sessionSupported) signal with the result.
241 	*/
242 	void isSessionSupported(in String session_mode)
243 	{
244 		checkClassBinding!(typeof(this))();
245 		ptrcall!(void)(GDNativeClassBinding.isSessionSupported, _godot_object, session_mode);
246 	}
247 	/**
248 	
249 	*/
250 	void setOptionalFeatures(in String optional_features)
251 	{
252 		checkClassBinding!(typeof(this))();
253 		ptrcall!(void)(GDNativeClassBinding.setOptionalFeatures, _godot_object, optional_features);
254 	}
255 	/**
256 	
257 	*/
258 	void setRequestedReferenceSpaceTypes(in String requested_reference_space_types)
259 	{
260 		checkClassBinding!(typeof(this))();
261 		ptrcall!(void)(GDNativeClassBinding.setRequestedReferenceSpaceTypes, _godot_object, requested_reference_space_types);
262 	}
263 	/**
264 	
265 	*/
266 	void setRequiredFeatures(in String required_features)
267 	{
268 		checkClassBinding!(typeof(this))();
269 		ptrcall!(void)(GDNativeClassBinding.setRequiredFeatures, _godot_object, required_features);
270 	}
271 	/**
272 	
273 	*/
274 	void setSessionMode(in String session_mode)
275 	{
276 		checkClassBinding!(typeof(this))();
277 		ptrcall!(void)(GDNativeClassBinding.setSessionMode, _godot_object, session_mode);
278 	}
279 	/**
280 	The vertices of a polygon which defines the boundaries of the user's play area.
281 	This will only be available if $(D referenceSpaceType) is `"bounded-floor"` and only on certain browsers and devices that support it.
282 	The $(D referenceSpaceReset) signal may indicate when this changes.
283 	*/
284 	@property PoolVector3Array boundsGeometry()
285 	{
286 		return getBoundsGeometry();
287 	}
288 	/**
289 	A comma-seperated list of optional features used by $(D ARVRInterface.initialize) when setting up the WebXR session.
290 	If a user's browser or device doesn't support one of the given features, initialization will continue, but you won't be able to use the requested feature.
291 	This doesn't have any effect on the interface when already initialized.
292 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType)WebXR's XRReferenceSpaceType$(D /url). If you want to use a particular reference space type, it must be listed in either $(D requiredFeatures) or $(D optionalFeatures).
293 	*/
294 	@property String optionalFeatures()
295 	{
296 		return getOptionalFeatures();
297 	}
298 	/// ditto
299 	@property void optionalFeatures(String v)
300 	{
301 		setOptionalFeatures(v);
302 	}
303 	/**
304 	The reference space type (from the list of requested types set in the $(D requestedReferenceSpaceTypes) property), that was ultimately used by $(D ARVRInterface.initialize) when setting up the WebXR session.
305 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType)WebXR's XRReferenceSpaceType$(D /url). If you want to use a particular reference space type, it must be listed in either $(D requiredFeatures) or $(D optionalFeatures).
306 	*/
307 	@property String referenceSpaceType()
308 	{
309 		return getReferenceSpaceType();
310 	}
311 	/**
312 	A comma-seperated list of reference space types used by $(D ARVRInterface.initialize) when setting up the WebXR session.
313 	The reference space types are requested in order, and the first on supported by the users device or browser will be used. The $(D referenceSpaceType) property contains the reference space type that was ultimately used.
314 	This doesn't have any effect on the interface when already initialized.
315 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType)WebXR's XRReferenceSpaceType$(D /url). If you want to use a particular reference space type, it must be listed in either $(D requiredFeatures) or $(D optionalFeatures).
316 	*/
317 	@property String requestedReferenceSpaceTypes()
318 	{
319 		return getRequestedReferenceSpaceTypes();
320 	}
321 	/// ditto
322 	@property void requestedReferenceSpaceTypes(String v)
323 	{
324 		setRequestedReferenceSpaceTypes(v);
325 	}
326 	/**
327 	A comma-seperated list of required features used by $(D ARVRInterface.initialize) when setting up the WebXR session.
328 	If a user's browser or device doesn't support one of the given features, initialization will fail and $(D sessionFailed) will be emitted.
329 	This doesn't have any effect on the interface when already initialized.
330 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType)WebXR's XRReferenceSpaceType$(D /url). If you want to use a particular reference space type, it must be listed in either $(D requiredFeatures) or $(D optionalFeatures).
331 	*/
332 	@property String requiredFeatures()
333 	{
334 		return getRequiredFeatures();
335 	}
336 	/// ditto
337 	@property void requiredFeatures(String v)
338 	{
339 		setRequiredFeatures(v);
340 	}
341 	/**
342 	The session mode used by $(D ARVRInterface.initialize) when setting up the WebXR session.
343 	This doesn't have any effect on the interface when already initialized.
344 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode)WebXR's XRSessionMode$(D /url), including: `"immersive-vr"`, `"immersive-ar"`, and `"inline"`.
345 	*/
346 	@property String sessionMode()
347 	{
348 		return getSessionMode();
349 	}
350 	/// ditto
351 	@property void sessionMode(String v)
352 	{
353 		setSessionMode(v);
354 	}
355 	/**
356 	Indicates if the WebXR session's imagery is visible to the user.
357 	Possible values come from $(D url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState)WebXR's XRVisibilityState$(D /url), including `"hidden"`, `"visible"`, and `"visible-blurred"`.
358 	*/
359 	@property String visibilityState()
360 	{
361 		return getVisibilityState();
362 	}
363 }