mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-11-22 00:48:09 +01:00
Removed the webxr module.
This commit is contained in:
parent
df568215f0
commit
e1349c85fa
@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
if env["platform"] == "javascript":
|
||||
env.AddJSLibraries(["native/library_godot_webxr.js"])
|
||||
env.AddJSExterns(["native/webxr.externs.js"])
|
||||
|
||||
env_webxr = env_modules.Clone()
|
||||
env_webxr.add_source_files(env.modules_sources, "*.cpp")
|
@ -1,14 +0,0 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return ["WebXRInterface"]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
@ -1,264 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="WebXRInterface" inherits="ARVRInterface" version="3.5">
|
||||
<brief_description>
|
||||
AR/VR interface using WebXR.
|
||||
</brief_description>
|
||||
<description>
|
||||
WebXR is an open standard that allows creating VR and AR applications that run in the web browser.
|
||||
As such, this interface is only available when running in an HTML5 export.
|
||||
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).
|
||||
Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to initialize than other AR/VR interfaces.
|
||||
Here's the minimum code required to start an immersive VR session:
|
||||
[codeblock]
|
||||
extends Spatial
|
||||
|
||||
var webxr_interface
|
||||
var vr_supported = false
|
||||
|
||||
func _ready():
|
||||
# We assume this node has a button as a child.
|
||||
# This button is for the user to consent to entering immersive VR mode.
|
||||
$Button.connect("pressed", self, "_on_Button_pressed")
|
||||
|
||||
webxr_interface = ARVRServer.find_interface("WebXR")
|
||||
if webxr_interface:
|
||||
# WebXR uses a lot of asynchronous callbacks, so we connect to various
|
||||
# signals in order to receive them.
|
||||
webxr_interface.connect("session_supported", self, "_webxr_session_supported")
|
||||
webxr_interface.connect("session_started", self, "_webxr_session_started")
|
||||
webxr_interface.connect("session_ended", self, "_webxr_session_ended")
|
||||
webxr_interface.connect("session_failed", self, "_webxr_session_failed")
|
||||
|
||||
# This returns immediately - our _webxr_session_supported() method
|
||||
# (which we connected to the "session_supported" signal above) will
|
||||
# be called sometime later to let us know if it's supported or not.
|
||||
webxr_interface.is_session_supported("immersive-vr")
|
||||
|
||||
func _webxr_session_supported(session_mode, supported):
|
||||
if session_mode == 'immersive-vr':
|
||||
vr_supported = supported
|
||||
|
||||
func _on_Button_pressed():
|
||||
if not vr_supported:
|
||||
OS.alert("Your browser doesn't support VR")
|
||||
return
|
||||
|
||||
# We want an immersive VR session, as opposed to AR ('immersive-ar') or a
|
||||
# simple 3DoF viewer ('viewer').
|
||||
webxr_interface.session_mode = 'immersive-vr'
|
||||
# 'bounded-floor' is room scale, 'local-floor' is a standing or sitting
|
||||
# experience (it puts you 1.6m above the ground if you have 3DoF headset),
|
||||
# whereas as 'local' puts you down at the ARVROrigin.
|
||||
# This list means it'll first try to request 'bounded-floor', then
|
||||
# fallback on 'local-floor' and ultimately 'local', if nothing else is
|
||||
# supported.
|
||||
webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local'
|
||||
# In order to use 'local-floor' or 'bounded-floor' we must also
|
||||
# mark the features as required or optional.
|
||||
webxr_interface.required_features = 'local-floor'
|
||||
webxr_interface.optional_features = 'bounded-floor'
|
||||
|
||||
# This will return false if we're unable to even request the session,
|
||||
# however, it can still fail asynchronously later in the process, so we
|
||||
# only know if it's really succeeded or failed when our
|
||||
# _webxr_session_started() or _webxr_session_failed() methods are called.
|
||||
if not webxr_interface.initialize():
|
||||
OS.alert("Failed to initialize")
|
||||
return
|
||||
|
||||
func _webxr_session_started():
|
||||
$Button.visible = false
|
||||
# This tells Godot to start rendering to the headset.
|
||||
get_viewport().arvr = true
|
||||
# This will be the reference space type you ultimately got, out of the
|
||||
# types that you requested above. This is useful if you want the game to
|
||||
# work a little differently in 'bounded-floor' versus 'local-floor'.
|
||||
print ("Reference space type: " + webxr_interface.reference_space_type)
|
||||
|
||||
func _webxr_session_ended():
|
||||
$Button.visible = true
|
||||
# If the user exits immersive mode, then we tell Godot to render to the web
|
||||
# page again.
|
||||
get_viewport().arvr = false
|
||||
|
||||
func _webxr_session_failed(message):
|
||||
OS.alert("Failed to initialize: " + message)
|
||||
[/codeblock]
|
||||
There are several ways to handle "controller" input:
|
||||
- Using [ARVRController] nodes and their [signal ARVRController.button_pressed] and [signal ARVRController.button_release] 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 [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
|
||||
- Using [method Node._unhandled_input] and [InputEventJoypadButton] or [InputEventJoypadMotion]. This works the same as normal joypads, except the [member 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 [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
|
||||
- Using the [signal select], [signal 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 [code]controller_id[/code] passed to these signals is the same id as used in [member ARVRController.controller_id].
|
||||
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 interactions with more advanced devices.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="How to make a VR game for WebXR with Godot">https://www.snopekgames.com/blog/2020/how-make-vr-game-webxr-godot</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_controller" qualifiers="const">
|
||||
<return type="ARVRPositionalTracker" />
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Gets an [ARVRPositionalTracker] for the given [code]controller_id[/code].
|
||||
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 [ARVRPositionalTracker] as a ray pointing at the object the user wishes to interact with.
|
||||
Use this method to get information about the controller that triggered one of these signals:
|
||||
- [signal selectstart]
|
||||
- [signal select]
|
||||
- [signal selectend]
|
||||
- [signal squeezestart]
|
||||
- [signal squeeze]
|
||||
- [signal squeezestart]
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_controller_target_ray_mode" qualifiers="const">
|
||||
<return type="int" enum="WebXRInterface.TargetRayMode" />
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Returns the target ray mode for the given [code]controller_id[/code].
|
||||
This can help interpret the input coming from that controller. See [url=https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource/targetRayMode]XRInputSource.targetRayMode[/url] for more information.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_session_supported">
|
||||
<return type="void" />
|
||||
<argument index="0" name="session_mode" type="String" />
|
||||
<description>
|
||||
Checks if the given [code]session_mode[/code] is supported by the user's browser.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
|
||||
This method returns nothing, instead it emits the [signal session_supported] signal with the result.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="bounds_geometry" type="PoolVector3Array" setter="" getter="get_bounds_geometry">
|
||||
The vertices of a polygon which defines the boundaries of the user's play area.
|
||||
This will only be available if [member reference_space_type] is [code]"bounded-floor"[/code] and only on certain browsers and devices that support it.
|
||||
The [signal reference_space_reset] signal may indicate when this changes.
|
||||
</member>
|
||||
<member name="optional_features" type="String" setter="set_optional_features" getter="get_optional_features">
|
||||
A comma-seperated list of optional features used by [method ARVRInterface.initialize] when setting up the WebXR session.
|
||||
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.
|
||||
This doesn't have any effect on the interface when already initialized.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
|
||||
</member>
|
||||
<member name="reference_space_type" type="String" setter="" getter="get_reference_space_type">
|
||||
The reference space type (from the list of requested types set in the [member requested_reference_space_types] property), that was ultimately used by [method ARVRInterface.initialize] when setting up the WebXR session.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
|
||||
</member>
|
||||
<member name="requested_reference_space_types" type="String" setter="set_requested_reference_space_types" getter="get_requested_reference_space_types">
|
||||
A comma-seperated list of reference space types used by [method ARVRInterface.initialize] when setting up the WebXR session.
|
||||
The reference space types are requested in order, and the first on supported by the users device or browser will be used. The [member reference_space_type] property contains the reference space type that was ultimately used.
|
||||
This doesn't have any effect on the interface when already initialized.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
|
||||
</member>
|
||||
<member name="required_features" type="String" setter="set_required_features" getter="get_required_features">
|
||||
A comma-seperated list of required features used by [method ARVRInterface.initialize] when setting up the WebXR session.
|
||||
If a user's browser or device doesn't support one of the given features, initialization will fail and [signal session_failed] will be emitted.
|
||||
This doesn't have any effect on the interface when already initialized.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
|
||||
</member>
|
||||
<member name="session_mode" type="String" setter="set_session_mode" getter="get_session_mode">
|
||||
The session mode used by [method ARVRInterface.initialize] when setting up the WebXR session.
|
||||
This doesn't have any effect on the interface when already initialized.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
|
||||
</member>
|
||||
<member name="visibility_state" type="String" setter="" getter="get_visibility_state">
|
||||
Indicates if the WebXR session's imagery is visible to the user.
|
||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="reference_space_reset">
|
||||
<description>
|
||||
Emitted to indicate that the reference space has been reset or reconfigured.
|
||||
When (or whether) this is emitted depends on the user's browser or device, but may include when the user has changed the dimensions of their play space (which you may be able to access via [member bounds_geometry]) or pressed/held a button to recenter their position.
|
||||
See [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace/reset_event]WebXR's XRReferenceSpace reset event[/url] for more information.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="select">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted after one of the "controllers" has finished its "primary action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="selectend">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted when one of the "controllers" has finished its "primary action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="selectstart">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted when one of the "controllers" has started its "primary action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_ended">
|
||||
<description>
|
||||
Emitted when the user ends the WebXR session (which can be done using UI from the browser or device).
|
||||
At this point, you should do [code]get_viewport().arvr = false[/code] to instruct Godot to resume rendering to the screen.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_failed">
|
||||
<argument index="0" name="message" type="String" />
|
||||
<description>
|
||||
Emitted by [method ARVRInterface.initialize] if the session fails to start.
|
||||
[code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_started">
|
||||
<description>
|
||||
Emitted by [method ARVRInterface.initialize] if the session is successfully started.
|
||||
At this point, it's safe to do [code]get_viewport().arvr = true[/code] to instruct Godot to start rendering to the AR/VR device.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="session_supported">
|
||||
<argument index="0" name="session_mode" type="String" />
|
||||
<argument index="1" name="supported" type="bool" />
|
||||
<description>
|
||||
Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="squeeze">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted after one of the "controllers" has finished its "primary squeeze action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="squeezeend">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted when one of the "controllers" has finished its "primary squeeze action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="squeezestart">
|
||||
<argument index="0" name="controller_id" type="int" />
|
||||
<description>
|
||||
Emitted when one of the "controllers" has started its "primary squeeze action".
|
||||
Use [method get_controller] to get more information about the controller.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="visibility_state_changed">
|
||||
<description>
|
||||
Emitted when [member visibility_state] has changed.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="TARGET_RAY_MODE_UNKNOWN" value="0" enum="TargetRayMode">
|
||||
We don't know the the target ray mode.
|
||||
</constant>
|
||||
<constant name="TARGET_RAY_MODE_GAZE" value="1" enum="TargetRayMode">
|
||||
Target ray originates at the viewer's eyes and points in the direction they are looking.
|
||||
</constant>
|
||||
<constant name="TARGET_RAY_MODE_TRACKED_POINTER" value="2" enum="TargetRayMode">
|
||||
Target ray from a handheld pointer, most likely a VR touch controller.
|
||||
</constant>
|
||||
<constant name="TARGET_RAY_MODE_SCREEN" value="3" enum="TargetRayMode">
|
||||
Target ray from touch screen, mouse or other tactile input device.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
@ -1,94 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* godot_webxr.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_WEBXR_H
|
||||
#define GODOT_WEBXR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stddef.h"
|
||||
|
||||
enum WebXRInputEvent {
|
||||
WEBXR_INPUT_EVENT_SELECTSTART,
|
||||
WEBXR_INPUT_EVENT_SELECTEND,
|
||||
WEBXR_INPUT_EVENT_SELECT,
|
||||
WEBXR_INPUT_EVENT_SQUEEZESTART,
|
||||
WEBXR_INPUT_EVENT_SQUEEZEEND,
|
||||
WEBXR_INPUT_EVENT_SQUEEZE,
|
||||
};
|
||||
|
||||
typedef void (*GodotWebXRSupportedCallback)(char *p_session_mode, int p_supported);
|
||||
typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type);
|
||||
typedef void (*GodotWebXREndedCallback)();
|
||||
typedef void (*GodotWebXRFailedCallback)(char *p_message);
|
||||
typedef void (*GodotWebXRControllerCallback)();
|
||||
typedef void (*GodotWebXRInputEventCallback)(int p_event_type, int p_controller_id);
|
||||
typedef void (*GodotWebXRSimpleEventCallback)(char *p_signal_name);
|
||||
|
||||
extern int godot_webxr_is_supported();
|
||||
extern void godot_webxr_is_session_supported(const char *p_session_mode, GodotWebXRSupportedCallback p_callback);
|
||||
|
||||
extern void godot_webxr_initialize(
|
||||
const char *p_session_mode,
|
||||
const char *p_required_features,
|
||||
const char *p_optional_features,
|
||||
const char *p_requested_reference_space_types,
|
||||
GodotWebXRStartedCallback p_on_session_started,
|
||||
GodotWebXREndedCallback p_on_session_ended,
|
||||
GodotWebXRFailedCallback p_on_session_failed,
|
||||
GodotWebXRControllerCallback p_on_controller_changed,
|
||||
GodotWebXRInputEventCallback p_on_input_event,
|
||||
GodotWebXRSimpleEventCallback p_on_simple_event);
|
||||
extern void godot_webxr_uninitialize();
|
||||
|
||||
extern int godot_webxr_get_view_count();
|
||||
extern int *godot_webxr_get_render_targetsize();
|
||||
extern float *godot_webxr_get_transform_for_eye(int p_eye);
|
||||
extern float *godot_webxr_get_projection_for_eye(int p_eye);
|
||||
extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_texture_id);
|
||||
|
||||
extern void godot_webxr_sample_controller_data();
|
||||
extern int godot_webxr_get_controller_count();
|
||||
extern int godot_webxr_is_controller_connected(int p_controller);
|
||||
extern float *godot_webxr_get_controller_transform(int p_controller);
|
||||
extern int *godot_webxr_get_controller_buttons(int p_controller);
|
||||
extern int *godot_webxr_get_controller_axes(int p_controller);
|
||||
extern int godot_webxr_get_controller_target_ray_mode(int p_controller);
|
||||
|
||||
extern char *godot_webxr_get_visibility_state();
|
||||
extern int *godot_webxr_get_bounds_geometry();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GODOT_WEBXR_H */
|
@ -1,642 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* library_godot_webxr.js */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
const GodotWebXR = {
|
||||
|
||||
$GodotWebXR__deps: ['$Browser', '$GL', '$GodotRuntime'],
|
||||
$GodotWebXR: {
|
||||
gl: null,
|
||||
|
||||
session: null,
|
||||
space: null,
|
||||
frame: null,
|
||||
pose: null,
|
||||
|
||||
// Monkey-patch the requestAnimationFrame() used by Emscripten for the main
|
||||
// loop, so that we can swap it out for XRSession.requestAnimationFrame()
|
||||
// when an XR session is started.
|
||||
orig_requestAnimationFrame: null,
|
||||
requestAnimationFrame: (callback) => {
|
||||
if (GodotWebXR.session && GodotWebXR.space) {
|
||||
const onFrame = function (time, frame) {
|
||||
GodotWebXR.frame = frame;
|
||||
GodotWebXR.pose = frame.getViewerPose(GodotWebXR.space);
|
||||
callback(time);
|
||||
GodotWebXR.frame = null;
|
||||
GodotWebXR.pose = null;
|
||||
};
|
||||
GodotWebXR.session.requestAnimationFrame(onFrame);
|
||||
} else {
|
||||
GodotWebXR.orig_requestAnimationFrame(callback);
|
||||
}
|
||||
},
|
||||
monkeyPatchRequestAnimationFrame: (enable) => {
|
||||
if (GodotWebXR.orig_requestAnimationFrame === null) {
|
||||
GodotWebXR.orig_requestAnimationFrame = Browser.requestAnimationFrame;
|
||||
}
|
||||
Browser.requestAnimationFrame = enable
|
||||
? GodotWebXR.requestAnimationFrame : GodotWebXR.orig_requestAnimationFrame;
|
||||
},
|
||||
pauseResumeMainLoop: () => {
|
||||
// Once both GodotWebXR.session and GodotWebXR.space are set or
|
||||
// unset, our monkey-patched requestAnimationFrame() should be
|
||||
// enabled or disabled. When using the WebXR API Emulator, this
|
||||
// gets picked up automatically, however, in the Oculus Browser
|
||||
// on the Quest, we need to pause and resume the main loop.
|
||||
Browser.mainLoop.pause();
|
||||
window.setTimeout(function () {
|
||||
Browser.mainLoop.resume();
|
||||
}, 0);
|
||||
},
|
||||
|
||||
// Some custom WebGL code for blitting our eye textures to the
|
||||
// framebuffer we get from WebXR.
|
||||
shaderProgram: null,
|
||||
programInfo: null,
|
||||
buffer: null,
|
||||
// Vertex shader source.
|
||||
vsSource: `
|
||||
const vec2 scale = vec2(0.5, 0.5);
|
||||
attribute vec4 aVertexPosition;
|
||||
|
||||
varying highp vec2 vTextureCoord;
|
||||
|
||||
void main () {
|
||||
gl_Position = aVertexPosition;
|
||||
vTextureCoord = aVertexPosition.xy * scale + scale;
|
||||
}
|
||||
`,
|
||||
// Fragment shader source.
|
||||
fsSource: `
|
||||
varying highp vec2 vTextureCoord;
|
||||
|
||||
uniform sampler2D uSampler;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(uSampler, vTextureCoord);
|
||||
}
|
||||
`,
|
||||
|
||||
initShaderProgram: (gl, vsSource, fsSource) => {
|
||||
const vertexShader = GodotWebXR.loadShader(gl, gl.VERTEX_SHADER, vsSource);
|
||||
const fragmentShader = GodotWebXR.loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
|
||||
|
||||
const shaderProgram = gl.createProgram();
|
||||
gl.attachShader(shaderProgram, vertexShader);
|
||||
gl.attachShader(shaderProgram, fragmentShader);
|
||||
gl.linkProgram(shaderProgram);
|
||||
|
||||
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
|
||||
GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return shaderProgram;
|
||||
},
|
||||
loadShader: (gl, type, source) => {
|
||||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`);
|
||||
gl.deleteShader(shader);
|
||||
return null;
|
||||
}
|
||||
|
||||
return shader;
|
||||
},
|
||||
initBuffer: (gl) => {
|
||||
const positionBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
const positions = [
|
||||
-1.0, -1.0,
|
||||
1.0, -1.0,
|
||||
-1.0, 1.0,
|
||||
1.0, 1.0,
|
||||
];
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
|
||||
return positionBuffer;
|
||||
},
|
||||
blitTexture: (gl, texture) => {
|
||||
if (GodotWebXR.shaderProgram === null) {
|
||||
GodotWebXR.shaderProgram = GodotWebXR.initShaderProgram(gl, GodotWebXR.vsSource, GodotWebXR.fsSource);
|
||||
GodotWebXR.programInfo = {
|
||||
program: GodotWebXR.shaderProgram,
|
||||
attribLocations: {
|
||||
vertexPosition: gl.getAttribLocation(GodotWebXR.shaderProgram, 'aVertexPosition'),
|
||||
},
|
||||
uniformLocations: {
|
||||
uSampler: gl.getUniformLocation(GodotWebXR.shaderProgram, 'uSampler'),
|
||||
},
|
||||
};
|
||||
GodotWebXR.buffer = GodotWebXR.initBuffer(gl);
|
||||
}
|
||||
|
||||
const orig_program = gl.getParameter(gl.CURRENT_PROGRAM);
|
||||
gl.useProgram(GodotWebXR.shaderProgram);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, GodotWebXR.buffer);
|
||||
gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler, 0);
|
||||
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
// Restore state.
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
gl.useProgram(orig_program);
|
||||
},
|
||||
|
||||
// Holds the controllers list between function calls.
|
||||
controllers: [],
|
||||
|
||||
// Updates controllers array, where the left hand (or sole tracker) is
|
||||
// the first element, and the right hand is the second element, and any
|
||||
// others placed at the 3rd position and up.
|
||||
sampleControllers: () => {
|
||||
if (!GodotWebXR.session) {
|
||||
return;
|
||||
}
|
||||
|
||||
let other_index = 2;
|
||||
const controllers = [];
|
||||
GodotWebXR.session.inputSources.forEach((input_source) => {
|
||||
if (input_source.targetRayMode === 'tracked-pointer') {
|
||||
if (input_source.handedness === 'right') {
|
||||
controllers[1] = input_source;
|
||||
} else if (input_source.handedness === 'left' || !controllers[0]) {
|
||||
controllers[0] = input_source;
|
||||
}
|
||||
} else {
|
||||
controllers[other_index++] = input_source;
|
||||
}
|
||||
});
|
||||
GodotWebXR.controllers = controllers;
|
||||
},
|
||||
|
||||
getControllerId: (input_source) => GodotWebXR.controllers.indexOf(input_source),
|
||||
},
|
||||
|
||||
godot_webxr_is_supported__proxy: 'sync',
|
||||
godot_webxr_is_supported__sig: 'i',
|
||||
godot_webxr_is_supported: function () {
|
||||
return !!navigator.xr;
|
||||
},
|
||||
|
||||
godot_webxr_is_session_supported__proxy: 'sync',
|
||||
godot_webxr_is_session_supported__sig: 'vii',
|
||||
godot_webxr_is_session_supported: function (p_session_mode, p_callback) {
|
||||
const session_mode = GodotRuntime.parseString(p_session_mode);
|
||||
const cb = GodotRuntime.get_func(p_callback);
|
||||
if (navigator.xr) {
|
||||
navigator.xr.isSessionSupported(session_mode).then(function (supported) {
|
||||
const c_str = GodotRuntime.allocString(session_mode);
|
||||
cb(c_str, supported ? 1 : 0);
|
||||
GodotRuntime.free(c_str);
|
||||
});
|
||||
} else {
|
||||
const c_str = GodotRuntime.allocString(session_mode);
|
||||
cb(c_str, 0);
|
||||
GodotRuntime.free(c_str);
|
||||
}
|
||||
},
|
||||
|
||||
godot_webxr_initialize__deps: ['emscripten_webgl_get_current_context'],
|
||||
godot_webxr_initialize__proxy: 'sync',
|
||||
godot_webxr_initialize__sig: 'viiiiiiiiii',
|
||||
godot_webxr_initialize: function (p_session_mode, p_required_features, p_optional_features, p_requested_reference_spaces, p_on_session_started, p_on_session_ended, p_on_session_failed, p_on_controller_changed, p_on_input_event, p_on_simple_event) {
|
||||
GodotWebXR.monkeyPatchRequestAnimationFrame(true);
|
||||
|
||||
const session_mode = GodotRuntime.parseString(p_session_mode);
|
||||
const required_features = GodotRuntime.parseString(p_required_features).split(',').map((s) => s.trim()).filter((s) => s !== '');
|
||||
const optional_features = GodotRuntime.parseString(p_optional_features).split(',').map((s) => s.trim()).filter((s) => s !== '');
|
||||
const requested_reference_space_types = GodotRuntime.parseString(p_requested_reference_spaces).split(',').map((s) => s.trim());
|
||||
const onstarted = GodotRuntime.get_func(p_on_session_started);
|
||||
const onended = GodotRuntime.get_func(p_on_session_ended);
|
||||
const onfailed = GodotRuntime.get_func(p_on_session_failed);
|
||||
const oncontroller = GodotRuntime.get_func(p_on_controller_changed);
|
||||
const oninputevent = GodotRuntime.get_func(p_on_input_event);
|
||||
const onsimpleevent = GodotRuntime.get_func(p_on_simple_event);
|
||||
|
||||
const session_init = {};
|
||||
if (required_features.length > 0) {
|
||||
session_init['requiredFeatures'] = required_features;
|
||||
}
|
||||
if (optional_features.length > 0) {
|
||||
session_init['optionalFeatures'] = optional_features;
|
||||
}
|
||||
|
||||
navigator.xr.requestSession(session_mode, session_init).then(function (session) {
|
||||
GodotWebXR.session = session;
|
||||
|
||||
session.addEventListener('end', function (evt) {
|
||||
onended();
|
||||
});
|
||||
|
||||
session.addEventListener('inputsourceschange', function (evt) {
|
||||
let controller_changed = false;
|
||||
[evt.added, evt.removed].forEach((lst) => {
|
||||
lst.forEach((input_source) => {
|
||||
if (input_source.targetRayMode === 'tracked-pointer') {
|
||||
controller_changed = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
if (controller_changed) {
|
||||
oncontroller();
|
||||
}
|
||||
});
|
||||
|
||||
['selectstart', 'selectend', 'select', 'squeezestart', 'squeezeend', 'squeeze'].forEach((input_event, index) => {
|
||||
session.addEventListener(input_event, function (evt) {
|
||||
// Some controllers won't exist until an event occurs,
|
||||
// for example, with "screen" input sources (touch).
|
||||
GodotWebXR.sampleControllers();
|
||||
oninputevent(index, GodotWebXR.getControllerId(evt.inputSource));
|
||||
});
|
||||
});
|
||||
|
||||
session.addEventListener('visibilitychange', function (evt) {
|
||||
const c_str = GodotRuntime.allocString('visibility_state_changed');
|
||||
onsimpleevent(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
});
|
||||
|
||||
const gl_context_handle = _emscripten_webgl_get_current_context(); // eslint-disable-line no-undef
|
||||
const gl = GL.getContext(gl_context_handle).GLctx;
|
||||
GodotWebXR.gl = gl;
|
||||
|
||||
gl.makeXRCompatible().then(function () {
|
||||
session.updateRenderState({
|
||||
baseLayer: new XRWebGLLayer(session, gl),
|
||||
});
|
||||
|
||||
function onReferenceSpaceSuccess(reference_space, reference_space_type) {
|
||||
GodotWebXR.space = reference_space;
|
||||
|
||||
// Using reference_space.addEventListener() crashes when
|
||||
// using the polyfill with the WebXR Emulator extension,
|
||||
// so we set the event property instead.
|
||||
reference_space.onreset = function (evt) {
|
||||
const c_str = GodotRuntime.allocString('reference_space_reset');
|
||||
onsimpleevent(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
};
|
||||
|
||||
// Now that both GodotWebXR.session and GodotWebXR.space are
|
||||
// set, we need to pause and resume the main loop for the XR
|
||||
// main loop to kick in.
|
||||
GodotWebXR.pauseResumeMainLoop();
|
||||
|
||||
// Call in setTimeout() so that errors in the onstarted()
|
||||
// callback don't bubble up here and cause Godot to try the
|
||||
// next reference space.
|
||||
window.setTimeout(function () {
|
||||
const c_str = GodotRuntime.allocString(reference_space_type);
|
||||
onstarted(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function requestReferenceSpace() {
|
||||
const reference_space_type = requested_reference_space_types.shift();
|
||||
session.requestReferenceSpace(reference_space_type)
|
||||
.then((refSpace) => {
|
||||
onReferenceSpaceSuccess(refSpace, reference_space_type);
|
||||
})
|
||||
.catch(() => {
|
||||
if (requested_reference_space_types.length === 0) {
|
||||
const c_str = GodotRuntime.allocString('Unable to get any of the requested reference space types');
|
||||
onfailed(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
} else {
|
||||
requestReferenceSpace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
requestReferenceSpace();
|
||||
}).catch(function (error) {
|
||||
const c_str = GodotRuntime.allocString(`Unable to make WebGL context compatible with WebXR: ${error}`);
|
||||
onfailed(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
});
|
||||
}).catch(function (error) {
|
||||
const c_str = GodotRuntime.allocString(`Unable to start session: ${error}`);
|
||||
onfailed(c_str);
|
||||
GodotRuntime.free(c_str);
|
||||
});
|
||||
},
|
||||
|
||||
godot_webxr_uninitialize__proxy: 'sync',
|
||||
godot_webxr_uninitialize__sig: 'v',
|
||||
godot_webxr_uninitialize: function () {
|
||||
if (GodotWebXR.session) {
|
||||
GodotWebXR.session.end()
|
||||
// Prevent exception when session has already ended.
|
||||
.catch((e) => { });
|
||||
}
|
||||
|
||||
GodotWebXR.session = null;
|
||||
GodotWebXR.space = null;
|
||||
GodotWebXR.frame = null;
|
||||
GodotWebXR.pose = null;
|
||||
|
||||
// Disable the monkey-patched window.requestAnimationFrame() and
|
||||
// pause/restart the main loop to activate it on all platforms.
|
||||
GodotWebXR.monkeyPatchRequestAnimationFrame(false);
|
||||
GodotWebXR.pauseResumeMainLoop();
|
||||
},
|
||||
|
||||
godot_webxr_get_view_count__proxy: 'sync',
|
||||
godot_webxr_get_view_count__sig: 'i',
|
||||
godot_webxr_get_view_count: function () {
|
||||
if (!GodotWebXR.session || !GodotWebXR.pose) {
|
||||
return 0;
|
||||
}
|
||||
return GodotWebXR.pose.views.length;
|
||||
},
|
||||
|
||||
godot_webxr_get_render_targetsize__proxy: 'sync',
|
||||
godot_webxr_get_render_targetsize__sig: 'i',
|
||||
godot_webxr_get_render_targetsize: function () {
|
||||
if (!GodotWebXR.session || !GodotWebXR.pose) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const glLayer = GodotWebXR.session.renderState.baseLayer;
|
||||
const view = GodotWebXR.pose.views[0];
|
||||
const viewport = glLayer.getViewport(view);
|
||||
|
||||
const buf = GodotRuntime.malloc(2 * 4);
|
||||
GodotRuntime.setHeapValue(buf + 0, viewport.width, 'i32');
|
||||
GodotRuntime.setHeapValue(buf + 4, viewport.height, 'i32');
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_get_transform_for_eye__proxy: 'sync',
|
||||
godot_webxr_get_transform_for_eye__sig: 'ii',
|
||||
godot_webxr_get_transform_for_eye: function (p_eye) {
|
||||
if (!GodotWebXR.session || !GodotWebXR.pose) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const views = GodotWebXR.pose.views;
|
||||
let matrix;
|
||||
if (p_eye === 0) {
|
||||
matrix = GodotWebXR.pose.transform.matrix;
|
||||
} else {
|
||||
matrix = views[p_eye - 1].transform.matrix;
|
||||
}
|
||||
const buf = GodotRuntime.malloc(16 * 4);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_get_projection_for_eye__proxy: 'sync',
|
||||
godot_webxr_get_projection_for_eye__sig: 'ii',
|
||||
godot_webxr_get_projection_for_eye: function (p_eye) {
|
||||
if (!GodotWebXR.session || !GodotWebXR.pose) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
|
||||
const matrix = GodotWebXR.pose.views[view_index].projectionMatrix;
|
||||
const buf = GodotRuntime.malloc(16 * 4);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_commit_for_eye__proxy: 'sync',
|
||||
godot_webxr_commit_for_eye__sig: 'vii',
|
||||
godot_webxr_commit_for_eye: function (p_eye, p_texture_id) {
|
||||
if (!GodotWebXR.session || !GodotWebXR.pose) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
|
||||
const glLayer = GodotWebXR.session.renderState.baseLayer;
|
||||
const view = GodotWebXR.pose.views[view_index];
|
||||
const viewport = glLayer.getViewport(view);
|
||||
const gl = GodotWebXR.gl;
|
||||
|
||||
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
||||
const orig_viewport = gl.getParameter(gl.VIEWPORT);
|
||||
|
||||
// Bind to WebXR's framebuffer.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
|
||||
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
||||
|
||||
GodotWebXR.blitTexture(gl, GL.textures[p_texture_id]);
|
||||
|
||||
// Restore state.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
|
||||
gl.viewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
|
||||
},
|
||||
|
||||
godot_webxr_sample_controller_data__proxy: 'sync',
|
||||
godot_webxr_sample_controller_data__sig: 'v',
|
||||
godot_webxr_sample_controller_data: function () {
|
||||
GodotWebXR.sampleControllers();
|
||||
},
|
||||
|
||||
godot_webxr_get_controller_count__proxy: 'sync',
|
||||
godot_webxr_get_controller_count__sig: 'i',
|
||||
godot_webxr_get_controller_count: function () {
|
||||
if (!GodotWebXR.session || !GodotWebXR.frame) {
|
||||
return 0;
|
||||
}
|
||||
return GodotWebXR.controllers.length;
|
||||
},
|
||||
|
||||
godot_webxr_is_controller_connected__proxy: 'sync',
|
||||
godot_webxr_is_controller_connected__sig: 'ii',
|
||||
godot_webxr_is_controller_connected: function (p_controller) {
|
||||
if (!GodotWebXR.session || !GodotWebXR.frame) {
|
||||
return false;
|
||||
}
|
||||
return !!GodotWebXR.controllers[p_controller];
|
||||
},
|
||||
|
||||
godot_webxr_get_controller_transform__proxy: 'sync',
|
||||
godot_webxr_get_controller_transform__sig: 'ii',
|
||||
godot_webxr_get_controller_transform: function (p_controller) {
|
||||
if (!GodotWebXR.session || !GodotWebXR.frame) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const controller = GodotWebXR.controllers[p_controller];
|
||||
if (!controller) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const frame = GodotWebXR.frame;
|
||||
const space = GodotWebXR.space;
|
||||
|
||||
const pose = frame.getPose(controller.targetRaySpace, space);
|
||||
if (!pose) {
|
||||
// This can mean that the controller lost tracking.
|
||||
return 0;
|
||||
}
|
||||
const matrix = pose.transform.matrix;
|
||||
|
||||
const buf = GodotRuntime.malloc(16 * 4);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
GodotRuntime.setHeapValue(buf + (i * 4), matrix[i], 'float');
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_get_controller_buttons__proxy: 'sync',
|
||||
godot_webxr_get_controller_buttons__sig: 'ii',
|
||||
godot_webxr_get_controller_buttons: function (p_controller) {
|
||||
if (GodotWebXR.controllers.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const controller = GodotWebXR.controllers[p_controller];
|
||||
if (!controller || !controller.gamepad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const button_count = controller.gamepad.buttons.length;
|
||||
|
||||
const buf = GodotRuntime.malloc((button_count + 1) * 4);
|
||||
GodotRuntime.setHeapValue(buf, button_count, 'i32');
|
||||
for (let i = 0; i < button_count; i++) {
|
||||
GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.buttons[i].value, 'float');
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_get_controller_axes__proxy: 'sync',
|
||||
godot_webxr_get_controller_axes__sig: 'ii',
|
||||
godot_webxr_get_controller_axes: function (p_controller) {
|
||||
if (GodotWebXR.controllers.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const controller = GodotWebXR.controllers[p_controller];
|
||||
if (!controller || !controller.gamepad) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const axes_count = controller.gamepad.axes.length;
|
||||
|
||||
const buf = GodotRuntime.malloc((axes_count + 1) * 4);
|
||||
GodotRuntime.setHeapValue(buf, axes_count, 'i32');
|
||||
for (let i = 0; i < axes_count; i++) {
|
||||
let value = controller.gamepad.axes[i];
|
||||
if (i === 1 || i === 3) {
|
||||
// Invert the Y-axis on thumbsticks and trackpads, in order to
|
||||
// match OpenXR and other XR platform SDKs.
|
||||
value *= -1.0;
|
||||
}
|
||||
GodotRuntime.setHeapValue(buf + 4 + (i * 4), value, 'float');
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
|
||||
godot_webxr_get_controller_target_ray_mode__proxy: 'sync',
|
||||
godot_webxr_get_controller_target_ray_mode__sig: 'ii',
|
||||
godot_webxr_get_controller_target_ray_mode: function (p_controller) {
|
||||
if (p_controller < 0 || p_controller >= GodotWebXR.controllers.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const controller = GodotWebXR.controllers[p_controller];
|
||||
if (!controller) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (controller.targetRayMode) {
|
||||
case 'gaze':
|
||||
return 1;
|
||||
|
||||
case 'tracked-pointer':
|
||||
return 2;
|
||||
|
||||
case 'screen':
|
||||
return 3;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
godot_webxr_get_visibility_state__proxy: 'sync',
|
||||
godot_webxr_get_visibility_state__sig: 'i',
|
||||
godot_webxr_get_visibility_state: function () {
|
||||
if (!GodotWebXR.session || !GodotWebXR.session.visibilityState) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GodotRuntime.allocString(GodotWebXR.session.visibilityState);
|
||||
},
|
||||
|
||||
godot_webxr_get_bounds_geometry__proxy: 'sync',
|
||||
godot_webxr_get_bounds_geometry__sig: 'i',
|
||||
godot_webxr_get_bounds_geometry: function () {
|
||||
if (!GodotWebXR.space || !GodotWebXR.space.boundsGeometry) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const point_count = GodotWebXR.space.boundsGeometry.length;
|
||||
if (point_count === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const buf = GodotRuntime.malloc(((point_count * 3) + 1) * 4);
|
||||
GodotRuntime.setHeapValue(buf, point_count, 'i32');
|
||||
for (let i = 0; i < point_count; i++) {
|
||||
const point = GodotWebXR.space.boundsGeometry[i];
|
||||
GodotRuntime.setHeapValue(buf + ((i * 3) + 1) * 4, point.x, 'float');
|
||||
GodotRuntime.setHeapValue(buf + ((i * 3) + 2) * 4, point.y, 'float');
|
||||
GodotRuntime.setHeapValue(buf + ((i * 3) + 3) * 4, point.z, 'float');
|
||||
}
|
||||
|
||||
return buf;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
autoAddDeps(GodotWebXR, '$GodotWebXR');
|
||||
mergeInto(LibraryManager.library, GodotWebXR);
|
@ -1,499 +0,0 @@
|
||||
/**
|
||||
* @type {XR}
|
||||
*/
|
||||
Navigator.prototype.xr;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRSessionInit() {};
|
||||
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
XRSessionInit.prototype.requiredFeatures;
|
||||
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
XRSessionInit.prototype.optionalFeatures;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XR() {}
|
||||
|
||||
/**
|
||||
* @type {?function (Event)}
|
||||
*/
|
||||
XR.prototype.ondevicechanged;
|
||||
|
||||
/**
|
||||
* @param {string} mode
|
||||
*
|
||||
* @return {!Promise<boolean>}
|
||||
*/
|
||||
XR.prototype.isSessionSupported = function(mode) {};
|
||||
|
||||
/**
|
||||
* @param {string} mode
|
||||
* @param {XRSessionInit} options
|
||||
*
|
||||
* @return {!Promise<XRSession>}
|
||||
*/
|
||||
XR.prototype.requestSession = function(mode, options) {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRSession() {}
|
||||
|
||||
/**
|
||||
* @type {XRRenderState}
|
||||
*/
|
||||
XRSession.prototype.renderState;
|
||||
|
||||
/**
|
||||
* @type {Array<XRInputSource>}
|
||||
*/
|
||||
XRSession.prototype.inputSources;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
XRSession.prototype.visibilityState;
|
||||
|
||||
/**
|
||||
* @type {?function (Event)}
|
||||
*/
|
||||
XRSession.prototype.onend;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourcesChangeEvent)}
|
||||
*/
|
||||
XRSession.prototype.oninputsourceschange;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onselectstart;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onselect;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onselectend;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onsqueezestart;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onsqueeze;
|
||||
|
||||
/**
|
||||
* @type {?function (XRInputSourceEvent)}
|
||||
*/
|
||||
XRSession.prototype.onsqueezeend;
|
||||
|
||||
/**
|
||||
* @type {?function (Event)}
|
||||
*/
|
||||
XRSession.prototype.onvisibilitychange;
|
||||
|
||||
/**
|
||||
* @param {XRRenderStateInit} state
|
||||
* @return {void}
|
||||
*/
|
||||
XRSession.prototype.updateRenderState = function (state) {};
|
||||
|
||||
/**
|
||||
* @param {XRFrameRequestCallback} callback
|
||||
* @return {number}
|
||||
*/
|
||||
XRSession.prototype.requestAnimationFrame = function (callback) {};
|
||||
|
||||
/**
|
||||
* @param {number} handle
|
||||
* @return {void}
|
||||
*/
|
||||
XRSession.prototype.cancelAnimationFrame = function (handle) {};
|
||||
|
||||
/**
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
XRSession.prototype.end = function () {};
|
||||
|
||||
/**
|
||||
* @param {string} referenceSpaceType
|
||||
* @return {Promise<XRReferenceSpace>}
|
||||
*/
|
||||
XRSession.prototype.requestReferenceSpace = function (referenceSpaceType) {};
|
||||
|
||||
/**
|
||||
* @typedef {function(number, XRFrame): undefined}
|
||||
*/
|
||||
var XRFrameRequestCallback;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRRenderStateInit() {}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRRenderStateInit.prototype.depthNear;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRRenderStateInit.prototype.depthFar;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRRenderStateInit.prototype.inlineVerticalFieldOfView;
|
||||
|
||||
/**
|
||||
* @type {?XRWebGLLayer}
|
||||
*/
|
||||
XRRenderStateInit.prototype.baseLayer;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRRenderState() {};
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRRenderState.prototype.depthNear;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRRenderState.prototype.depthFar;
|
||||
|
||||
/**
|
||||
* @type {?number}
|
||||
*/
|
||||
XRRenderState.prototype.inlineVerticalFieldOfView;
|
||||
|
||||
/**
|
||||
* @type {?XRWebGLLayer}
|
||||
*/
|
||||
XRRenderState.prototype.baseLayer;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRFrame() {}
|
||||
|
||||
/**
|
||||
* @type {XRSession}
|
||||
*/
|
||||
XRFrame.prototype.session;
|
||||
|
||||
/**
|
||||
* @param {XRReferenceSpace} referenceSpace
|
||||
* @return {?XRViewerPose}
|
||||
*/
|
||||
XRFrame.prototype.getViewerPose = function (referenceSpace) {};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {XRSpace} space
|
||||
* @param {XRSpace} baseSpace
|
||||
* @return {XRPose}
|
||||
*/
|
||||
XRFrame.prototype.getPose = function (space, baseSpace) {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRReferenceSpace() {};
|
||||
|
||||
/**
|
||||
* @type {Array<DOMPointReadOnly>}
|
||||
*/
|
||||
XRReferenceSpace.prototype.boundsGeometry;
|
||||
|
||||
/**
|
||||
* @param {XRRigidTransform} originOffset
|
||||
* @return {XRReferenceSpace}
|
||||
*/
|
||||
XRReferenceSpace.prototype.getOffsetReferenceSpace = function(originOffset) {};
|
||||
|
||||
/**
|
||||
* @type {?function (Event)}
|
||||
*/
|
||||
XRReferenceSpace.prototype.onreset;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRRigidTransform() {};
|
||||
|
||||
/**
|
||||
* @type {DOMPointReadOnly}
|
||||
*/
|
||||
XRRigidTransform.prototype.position;
|
||||
|
||||
/**
|
||||
* @type {DOMPointReadOnly}
|
||||
*/
|
||||
XRRigidTransform.prototype.orientation;
|
||||
|
||||
/**
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
XRRigidTransform.prototype.matrix;
|
||||
|
||||
/**
|
||||
* @type {XRRigidTransform}
|
||||
*/
|
||||
XRRigidTransform.prototype.inverse;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRView() {}
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
XRView.prototype.eye;
|
||||
|
||||
/**
|
||||
* @type {Float32Array}
|
||||
*/
|
||||
XRView.prototype.projectionMatrix;
|
||||
|
||||
/**
|
||||
* @type {XRRigidTransform}
|
||||
*/
|
||||
XRView.prototype.transform;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRViewerPose() {}
|
||||
|
||||
/**
|
||||
* @type {Array<XRView>}
|
||||
*/
|
||||
XRViewerPose.prototype.views;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRViewport() {}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRViewport.prototype.x;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRViewport.prototype.y;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRViewport.prototype.width;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRViewport.prototype.height;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRWebGLLayerInit() {};
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.antialias;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.depth;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.stencil;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.alpha;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.ignoreDepthValues;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.ignoreDepthValues;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRWebGLLayerInit.prototype.framebufferScaleFactor;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {XRSession} session
|
||||
* @param {WebGLRenderContext|WebGL2RenderingContext} ctx
|
||||
* @param {?XRWebGLLayerInit} options
|
||||
*/
|
||||
function XRWebGLLayer(session, ctx, options) {}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayer.prototype.antialias;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRWebGLLayer.prototype.ignoreDepthValues;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRWebGLLayer.prototype.framebufferWidth;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
XRWebGLLayer.prototype.framebufferHeight;
|
||||
|
||||
/**
|
||||
* @type {WebGLFramebuffer}
|
||||
*/
|
||||
XRWebGLLayer.prototype.framebuffer;
|
||||
|
||||
/**
|
||||
* @param {XRView} view
|
||||
* @return {?XRViewport}
|
||||
*/
|
||||
XRWebGLLayer.prototype.getViewport = function(view) {};
|
||||
|
||||
/**
|
||||
* @param {XRSession} session
|
||||
* @return {number}
|
||||
*/
|
||||
XRWebGLLayer.prototype.getNativeFramebufferScaleFactor = function (session) {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function WebGLRenderingContextBase() {};
|
||||
|
||||
/**
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
WebGLRenderingContextBase.prototype.makeXRCompatible = function () {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRInputSourcesChangeEvent() {};
|
||||
|
||||
/**
|
||||
* @type {Array<XRInputSource>}
|
||||
*/
|
||||
XRInputSourcesChangeEvent.prototype.added;
|
||||
|
||||
/**
|
||||
* @type {Array<XRInputSource>}
|
||||
*/
|
||||
XRInputSourcesChangeEvent.prototype.removed;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRInputSourceEvent() {};
|
||||
|
||||
/**
|
||||
* @type {XRFrame}
|
||||
*/
|
||||
XRInputSourceEvent.prototype.frame;
|
||||
|
||||
/**
|
||||
* @type {XRInputSource}
|
||||
*/
|
||||
XRInputSourceEvent.prototype.inputSource;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRInputSource() {};
|
||||
|
||||
/**
|
||||
* @type {Gamepad}
|
||||
*/
|
||||
XRInputSource.prototype.gamepad;
|
||||
|
||||
/**
|
||||
* @type {XRSpace}
|
||||
*/
|
||||
XRInputSource.prototype.gripSpace;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
XRInputSource.prototype.handedness;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
XRInputSource.prototype.profiles;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
XRInputSource.prototype.targetRayMode;
|
||||
|
||||
/**
|
||||
* @type {XRSpace}
|
||||
*/
|
||||
XRInputSource.prototype.targetRaySpace;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRSpace() {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function XRPose() {};
|
||||
|
||||
/**
|
||||
* @type {XRRigidTransform}
|
||||
*/
|
||||
XRPose.prototype.transform;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
XRPose.prototype.emulatedPosition;
|
@ -1,47 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "webxr_interface.h"
|
||||
#include "webxr_interface_js.h"
|
||||
|
||||
void register_webxr_types() {
|
||||
ClassDB::register_virtual_class<WebXRInterface>();
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
Ref<WebXRInterfaceJS> webxr;
|
||||
webxr.instance();
|
||||
ARVRServer::get_singleton()->add_interface(webxr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_webxr_types() {
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef WEBXR_REGISTER_TYPES_H
|
||||
#define WEBXR_REGISTER_TYPES_H
|
||||
|
||||
void register_webxr_types();
|
||||
void unregister_webxr_types();
|
||||
|
||||
#endif // WEBXR_REGISTER_TYPES_H
|
@ -1,77 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webxr_interface.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "webxr_interface.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void WebXRInterface::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("is_session_supported", "session_mode"), &WebXRInterface::is_session_supported);
|
||||
ClassDB::bind_method(D_METHOD("set_session_mode", "session_mode"), &WebXRInterface::set_session_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_session_mode"), &WebXRInterface::get_session_mode);
|
||||
ClassDB::bind_method(D_METHOD("set_required_features", "required_features"), &WebXRInterface::set_required_features);
|
||||
ClassDB::bind_method(D_METHOD("get_required_features"), &WebXRInterface::get_required_features);
|
||||
ClassDB::bind_method(D_METHOD("set_optional_features", "optional_features"), &WebXRInterface::set_optional_features);
|
||||
ClassDB::bind_method(D_METHOD("get_optional_features"), &WebXRInterface::get_optional_features);
|
||||
ClassDB::bind_method(D_METHOD("get_reference_space_type"), &WebXRInterface::get_reference_space_type);
|
||||
ClassDB::bind_method(D_METHOD("set_requested_reference_space_types", "requested_reference_space_types"), &WebXRInterface::set_requested_reference_space_types);
|
||||
ClassDB::bind_method(D_METHOD("get_requested_reference_space_types"), &WebXRInterface::get_requested_reference_space_types);
|
||||
ClassDB::bind_method(D_METHOD("get_controller", "controller_id"), &WebXRInterface::get_controller);
|
||||
ClassDB::bind_method(D_METHOD("get_controller_target_ray_mode", "controller_id"), &WebXRInterface::get_controller_target_ray_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
|
||||
ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_mode", PROPERTY_HINT_NONE), "set_session_mode", "get_session_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "required_features", PROPERTY_HINT_NONE), "set_required_features", "get_required_features");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "optional_features", PROPERTY_HINT_NONE), "set_optional_features", "get_optional_features");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "requested_reference_space_types", PROPERTY_HINT_NONE), "set_requested_reference_space_types", "get_requested_reference_space_types");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "bounds_geometry", PROPERTY_HINT_NONE), "", "get_bounds_geometry");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
|
||||
ADD_SIGNAL(MethodInfo("session_started"));
|
||||
ADD_SIGNAL(MethodInfo("session_ended"));
|
||||
ADD_SIGNAL(MethodInfo("session_failed", PropertyInfo(Variant::STRING, "message")));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("selectstart", PropertyInfo(Variant::INT, "controller_id")));
|
||||
ADD_SIGNAL(MethodInfo("select", PropertyInfo(Variant::INT, "controller_id")));
|
||||
ADD_SIGNAL(MethodInfo("selectend", PropertyInfo(Variant::INT, "controller_id")));
|
||||
ADD_SIGNAL(MethodInfo("squeezestart", PropertyInfo(Variant::INT, "controller_id")));
|
||||
ADD_SIGNAL(MethodInfo("squeeze", PropertyInfo(Variant::INT, "controller_id")));
|
||||
ADD_SIGNAL(MethodInfo("squeezeend", PropertyInfo(Variant::INT, "controller_id")));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("visibility_state_changed"));
|
||||
ADD_SIGNAL(MethodInfo("reference_space_reset"));
|
||||
|
||||
BIND_ENUM_CONSTANT(TARGET_RAY_MODE_UNKNOWN);
|
||||
BIND_ENUM_CONSTANT(TARGET_RAY_MODE_GAZE);
|
||||
BIND_ENUM_CONSTANT(TARGET_RAY_MODE_TRACKED_POINTER);
|
||||
BIND_ENUM_CONSTANT(TARGET_RAY_MODE_SCREEN);
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webxr_interface.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef WEBXR_INTERFACE_H
|
||||
#define WEBXR_INTERFACE_H
|
||||
|
||||
#include "servers/arvr/arvr_interface.h"
|
||||
#include "servers/arvr/arvr_positional_tracker.h"
|
||||
|
||||
/**
|
||||
@author David Snopek <david.snopek@snopekgames.com>
|
||||
|
||||
The WebXR interface is a VR/AR interface that can be used on the web.
|
||||
*/
|
||||
|
||||
class WebXRInterface : public ARVRInterface {
|
||||
GDCLASS(WebXRInterface, ARVRInterface);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
enum TargetRayMode {
|
||||
TARGET_RAY_MODE_UNKNOWN,
|
||||
TARGET_RAY_MODE_GAZE,
|
||||
TARGET_RAY_MODE_TRACKED_POINTER,
|
||||
TARGET_RAY_MODE_SCREEN,
|
||||
};
|
||||
|
||||
virtual void is_session_supported(const String &p_session_mode) = 0;
|
||||
virtual void set_session_mode(String p_session_mode) = 0;
|
||||
virtual String get_session_mode() const = 0;
|
||||
virtual void set_required_features(String p_required_features) = 0;
|
||||
virtual String get_required_features() const = 0;
|
||||
virtual void set_optional_features(String p_optional_features) = 0;
|
||||
virtual String get_optional_features() const = 0;
|
||||
virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0;
|
||||
virtual String get_requested_reference_space_types() const = 0;
|
||||
virtual String get_reference_space_type() const = 0;
|
||||
virtual Ref<ARVRPositionalTracker> get_controller(int p_controller_id) const = 0;
|
||||
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const = 0;
|
||||
virtual String get_visibility_state() const = 0;
|
||||
virtual PoolVector3Array get_bounds_geometry() const = 0;
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(WebXRInterface::TargetRayMode);
|
||||
|
||||
#endif // WEBXR_INTERFACE_H
|
@ -1,581 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webxr_interface_js.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webxr_interface_js.h"
|
||||
#include "core/os/input.h"
|
||||
#include "core/os/os.h"
|
||||
#include "emscripten.h"
|
||||
#include "godot_webxr.h"
|
||||
#include "main/input_default.h"
|
||||
#include "servers/visual/visual_server_globals.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
String session_mode = String(p_session_mode);
|
||||
interface->emit_signal("session_supported", session_mode, p_supported ? true : false);
|
||||
}
|
||||
|
||||
void _emwebxr_on_session_started(char *p_reference_space_type) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
String reference_space_type = String(p_reference_space_type);
|
||||
((WebXRInterfaceJS *)interface.ptr())->_set_reference_space_type(reference_space_type);
|
||||
interface->emit_signal("session_started");
|
||||
}
|
||||
|
||||
void _emwebxr_on_session_ended() {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
interface->uninitialize();
|
||||
interface->emit_signal("session_ended");
|
||||
}
|
||||
|
||||
void _emwebxr_on_session_failed(char *p_message) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
interface->uninitialize();
|
||||
|
||||
String message = String(p_message);
|
||||
interface->emit_signal("session_failed", message);
|
||||
}
|
||||
|
||||
void _emwebxr_on_controller_changed() {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
((WebXRInterfaceJS *)interface.ptr())->_on_controller_changed();
|
||||
}
|
||||
|
||||
extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_input_event(int p_event_type, int p_input_source) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
((WebXRInterfaceJS *)interface.ptr())->_on_input_event(p_event_type, p_input_source);
|
||||
}
|
||||
|
||||
extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_simple_event(char *p_signal_name) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRInterface> interface = arvr_server->find_interface("WebXR");
|
||||
ERR_FAIL_COND(interface.is_null());
|
||||
|
||||
StringName signal_name = StringName(p_signal_name);
|
||||
interface->emit_signal(signal_name);
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::is_session_supported(const String &p_session_mode) {
|
||||
godot_webxr_is_session_supported(p_session_mode.utf8().get_data(), &_emwebxr_on_session_supported);
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::set_session_mode(String p_session_mode) {
|
||||
session_mode = p_session_mode;
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_session_mode() const {
|
||||
return session_mode;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::set_required_features(String p_required_features) {
|
||||
required_features = p_required_features;
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_required_features() const {
|
||||
return required_features;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::set_optional_features(String p_optional_features) {
|
||||
optional_features = p_optional_features;
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_optional_features() const {
|
||||
return optional_features;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::set_requested_reference_space_types(String p_requested_reference_space_types) {
|
||||
requested_reference_space_types = p_requested_reference_space_types;
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_requested_reference_space_types() const {
|
||||
return requested_reference_space_types;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::_set_reference_space_type(String p_reference_space_type) {
|
||||
reference_space_type = p_reference_space_type;
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_reference_space_type() const {
|
||||
return reference_space_type;
|
||||
}
|
||||
|
||||
Ref<ARVRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(arvr_server, nullptr);
|
||||
|
||||
return arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
|
||||
}
|
||||
|
||||
WebXRInterface::TargetRayMode WebXRInterfaceJS::get_controller_target_ray_mode(int p_controller_id) const {
|
||||
ERR_FAIL_COND_V(p_controller_id <= 0, WebXRInterface::TARGET_RAY_MODE_UNKNOWN);
|
||||
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(arvr_server, WebXRInterface::TARGET_RAY_MODE_UNKNOWN);
|
||||
|
||||
return (WebXRInterface::TargetRayMode)godot_webxr_get_controller_target_ray_mode(p_controller_id - 1);
|
||||
}
|
||||
|
||||
String WebXRInterfaceJS::get_visibility_state() const {
|
||||
char *c_str = godot_webxr_get_visibility_state();
|
||||
if (c_str) {
|
||||
String visibility_state = String(c_str);
|
||||
free(c_str);
|
||||
|
||||
return visibility_state;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
PoolVector3Array WebXRInterfaceJS::get_bounds_geometry() const {
|
||||
PoolVector3Array ret;
|
||||
|
||||
int *js_bounds = godot_webxr_get_bounds_geometry();
|
||||
if (js_bounds) {
|
||||
ret.resize(js_bounds[0]);
|
||||
for (int i = 0; i < js_bounds[0]; i++) {
|
||||
float *js_vector3 = ((float *)js_bounds) + (i * 3) + 1;
|
||||
ret.set(i, Vector3(js_vector3[0], js_vector3[1], js_vector3[2]));
|
||||
}
|
||||
free(js_bounds);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
StringName WebXRInterfaceJS::get_name() const {
|
||||
return "WebXR";
|
||||
};
|
||||
|
||||
int WebXRInterfaceJS::get_capabilities() const {
|
||||
return ARVRInterface::ARVR_STEREO | ARVRInterface::ARVR_MONO;
|
||||
};
|
||||
|
||||
bool WebXRInterfaceJS::is_stereo() {
|
||||
return godot_webxr_get_view_count() == 2;
|
||||
};
|
||||
|
||||
bool WebXRInterfaceJS::is_initialized() const {
|
||||
return (initialized);
|
||||
};
|
||||
|
||||
bool WebXRInterfaceJS::initialize() {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(arvr_server, false);
|
||||
|
||||
if (!initialized) {
|
||||
if (!godot_webxr_is_supported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requested_reference_space_types.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make this our primary interface
|
||||
arvr_server->set_primary_interface(this);
|
||||
|
||||
// Clear state variables.
|
||||
memset(controllers_state, 0, sizeof controllers_state);
|
||||
memset(touching, 0, sizeof touching);
|
||||
|
||||
// Clear render_targetsize to make sure it gets reset to the new size.
|
||||
// Clearing in uninitialize() doesn't work because a frame can still be
|
||||
// rendered after it's called, which will fill render_targetsize again.
|
||||
render_targetsize.width = 0;
|
||||
render_targetsize.height = 0;
|
||||
|
||||
initialized = true;
|
||||
|
||||
godot_webxr_initialize(
|
||||
session_mode.utf8().get_data(),
|
||||
required_features.utf8().get_data(),
|
||||
optional_features.utf8().get_data(),
|
||||
requested_reference_space_types.utf8().get_data(),
|
||||
&_emwebxr_on_session_started,
|
||||
&_emwebxr_on_session_ended,
|
||||
&_emwebxr_on_session_failed,
|
||||
&_emwebxr_on_controller_changed,
|
||||
&_emwebxr_on_input_event,
|
||||
&_emwebxr_on_simple_event);
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
void WebXRInterfaceJS::uninitialize() {
|
||||
if (initialized) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
if (arvr_server != NULL) {
|
||||
// no longer our primary interface
|
||||
arvr_server->clear_primary_interface_if(this);
|
||||
}
|
||||
|
||||
godot_webxr_uninitialize();
|
||||
|
||||
reference_space_type = "";
|
||||
initialized = false;
|
||||
};
|
||||
};
|
||||
|
||||
Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
|
||||
Transform transform;
|
||||
|
||||
transform.basis.elements[0].x = p_js_matrix[0];
|
||||
transform.basis.elements[1].x = p_js_matrix[1];
|
||||
transform.basis.elements[2].x = p_js_matrix[2];
|
||||
transform.basis.elements[0].y = p_js_matrix[4];
|
||||
transform.basis.elements[1].y = p_js_matrix[5];
|
||||
transform.basis.elements[2].y = p_js_matrix[6];
|
||||
transform.basis.elements[0].z = p_js_matrix[8];
|
||||
transform.basis.elements[1].z = p_js_matrix[9];
|
||||
transform.basis.elements[2].z = p_js_matrix[10];
|
||||
transform.origin.x = p_js_matrix[12];
|
||||
transform.origin.y = p_js_matrix[13];
|
||||
transform.origin.z = p_js_matrix[14];
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
Size2 WebXRInterfaceJS::get_render_targetsize() {
|
||||
if (render_targetsize.width != 0 && render_targetsize.height != 0) {
|
||||
return render_targetsize;
|
||||
}
|
||||
|
||||
int *js_size = godot_webxr_get_render_targetsize();
|
||||
if (!initialized || js_size == nullptr) {
|
||||
// As a temporary default (until WebXR is fully initialized), use half the window size.
|
||||
Size2 temp = OS::get_singleton()->get_window_size();
|
||||
temp.width /= 2.0;
|
||||
return temp;
|
||||
}
|
||||
|
||||
render_targetsize.width = js_size[0];
|
||||
render_targetsize.height = js_size[1];
|
||||
|
||||
free(js_size);
|
||||
|
||||
return render_targetsize;
|
||||
};
|
||||
|
||||
Transform WebXRInterfaceJS::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
|
||||
Transform transform_for_eye;
|
||||
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
|
||||
|
||||
float *js_matrix = godot_webxr_get_transform_for_eye(p_eye);
|
||||
if (!initialized || js_matrix == nullptr) {
|
||||
transform_for_eye = p_cam_transform;
|
||||
return transform_for_eye;
|
||||
}
|
||||
|
||||
transform_for_eye = _js_matrix_to_transform(js_matrix);
|
||||
free(js_matrix);
|
||||
|
||||
return p_cam_transform * arvr_server->get_reference_frame() * transform_for_eye;
|
||||
};
|
||||
|
||||
CameraMatrix WebXRInterfaceJS::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
|
||||
CameraMatrix eye;
|
||||
|
||||
float *js_matrix = godot_webxr_get_projection_for_eye(p_eye);
|
||||
if (!initialized || js_matrix == nullptr) {
|
||||
return eye;
|
||||
}
|
||||
|
||||
int k = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
eye.matrix[i][j] = js_matrix[k++];
|
||||
}
|
||||
}
|
||||
|
||||
free(js_matrix);
|
||||
|
||||
// Copied from godot_oculus_mobile's ovr_mobile_session.cpp
|
||||
eye.matrix[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near);
|
||||
eye.matrix[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near);
|
||||
|
||||
return eye;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
RID texture = VSG::storage->render_target_get_texture(p_render_target);
|
||||
uint32_t texture_id = VSG::storage->texture_get_texid(texture);
|
||||
|
||||
godot_webxr_commit_for_eye(p_eye, texture_id);
|
||||
};
|
||||
|
||||
void WebXRInterfaceJS::process() {
|
||||
if (initialized) {
|
||||
godot_webxr_sample_controller_data();
|
||||
|
||||
int controller_count = godot_webxr_get_controller_count();
|
||||
if (controller_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < controller_count; i++) {
|
||||
_update_tracker(i);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
|
||||
ARVRServer *arvr_server = ARVRServer::get_singleton();
|
||||
ERR_FAIL_NULL(arvr_server);
|
||||
|
||||
Ref<ARVRPositionalTracker> tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id + 1);
|
||||
if (godot_webxr_is_controller_connected(p_controller_id)) {
|
||||
if (tracker.is_null()) {
|
||||
tracker.instance();
|
||||
tracker->set_type(ARVRServer::TRACKER_CONTROLLER);
|
||||
// Controller id's 0 and 1 are always the left and right hands.
|
||||
if (p_controller_id < 2) {
|
||||
tracker->set_name(p_controller_id == 0 ? "Left" : "Right");
|
||||
tracker->set_hand(p_controller_id == 0 ? ARVRPositionalTracker::TRACKER_LEFT_HAND : ARVRPositionalTracker::TRACKER_RIGHT_HAND);
|
||||
}
|
||||
// Use the ids we're giving to our "virtual" gamepads.
|
||||
tracker->set_joy_id(p_controller_id + 100);
|
||||
arvr_server->add_tracker(tracker);
|
||||
}
|
||||
|
||||
InputDefault *input = (InputDefault *)Input::get_singleton();
|
||||
int joy_id = p_controller_id + 100;
|
||||
|
||||
float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id);
|
||||
if (tracker_matrix) {
|
||||
Transform transform = _js_matrix_to_transform(tracker_matrix);
|
||||
tracker->set_position(transform.origin);
|
||||
tracker->set_orientation(transform.basis);
|
||||
free(tracker_matrix);
|
||||
}
|
||||
|
||||
int *buttons = godot_webxr_get_controller_buttons(p_controller_id);
|
||||
if (buttons) {
|
||||
for (int i = 0; i < buttons[0]; i++) {
|
||||
input->joy_button(joy_id, i, *((float *)buttons + (i + 1)));
|
||||
}
|
||||
free(buttons);
|
||||
}
|
||||
|
||||
int *axes = godot_webxr_get_controller_axes(p_controller_id);
|
||||
if (axes) {
|
||||
WebXRInterface::TargetRayMode target_ray_mode = (WebXRInterface::TargetRayMode)godot_webxr_get_controller_target_ray_mode(p_controller_id);
|
||||
if (target_ray_mode == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
|
||||
int touch_index = _get_touch_index(p_controller_id);
|
||||
if (touch_index < 5 && touching[touch_index]) {
|
||||
Vector2 joy_vector = _get_joy_vector_from_axes(axes);
|
||||
Vector2 previous_joy_vector(input->get_joy_axis(joy_id, 0), input->get_joy_axis(joy_id, 1));
|
||||
|
||||
if (!joy_vector.is_equal_approx(previous_joy_vector)) {
|
||||
Vector2 position = _get_screen_position_from_joy_vector(joy_vector);
|
||||
Vector2 previous_position = _get_screen_position_from_joy_vector(previous_joy_vector);
|
||||
|
||||
Ref<InputEventScreenDrag> event;
|
||||
event.instance();
|
||||
event->set_index(touch_index);
|
||||
event->set_position(position);
|
||||
event->set_relative(position - previous_position);
|
||||
input->parse_input_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < axes[0]; i++) {
|
||||
float value = *((float *)axes + (i + 1));
|
||||
input->joy_axis(joy_id, i, value);
|
||||
}
|
||||
|
||||
free(axes);
|
||||
}
|
||||
} else if (tracker.is_valid()) {
|
||||
arvr_server->remove_tracker(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::_on_controller_changed() {
|
||||
// Register "virtual" gamepads with Godot for the ones we get from WebXR.
|
||||
godot_webxr_sample_controller_data();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bool controller_connected = godot_webxr_is_controller_connected(i);
|
||||
if (controllers_state[i] != controller_connected) {
|
||||
Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", "");
|
||||
controllers_state[i] = controller_connected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::_on_input_event(int p_event_type, int p_input_source) {
|
||||
if (p_event_type == WEBXR_INPUT_EVENT_SELECTSTART || p_event_type == WEBXR_INPUT_EVENT_SELECTEND) {
|
||||
int target_ray_mode = godot_webxr_get_controller_target_ray_mode(p_input_source);
|
||||
if (target_ray_mode == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
|
||||
int touch_index = _get_touch_index(p_input_source);
|
||||
if (touch_index < 5) {
|
||||
touching[touch_index] = (p_event_type == WEBXR_INPUT_EVENT_SELECTSTART);
|
||||
}
|
||||
|
||||
int *axes = godot_webxr_get_controller_axes(p_input_source);
|
||||
if (axes) {
|
||||
Vector2 joy_vector = _get_joy_vector_from_axes(axes);
|
||||
Vector2 position = _get_screen_position_from_joy_vector(joy_vector);
|
||||
free(axes);
|
||||
|
||||
InputDefault *input = (InputDefault *)Input::get_singleton();
|
||||
|
||||
int joy_id = p_input_source + 100;
|
||||
input->set_joy_axis(joy_id, 0, joy_vector.x);
|
||||
input->set_joy_axis(joy_id, 1, joy_vector.y);
|
||||
|
||||
Ref<InputEventScreenTouch> event;
|
||||
event.instance();
|
||||
event->set_index(touch_index);
|
||||
event->set_position(position);
|
||||
event->set_pressed(p_event_type == WEBXR_INPUT_EVENT_SELECTSTART);
|
||||
Input::get_singleton()->parse_input_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int controller_id = p_input_source + 1;
|
||||
switch (p_event_type) {
|
||||
case WEBXR_INPUT_EVENT_SELECTSTART:
|
||||
emit_signal("selectstart", controller_id);
|
||||
break;
|
||||
|
||||
case WEBXR_INPUT_EVENT_SELECTEND:
|
||||
emit_signal("selectend", controller_id);
|
||||
break;
|
||||
|
||||
case WEBXR_INPUT_EVENT_SELECT:
|
||||
emit_signal("select", controller_id);
|
||||
break;
|
||||
|
||||
case WEBXR_INPUT_EVENT_SQUEEZESTART:
|
||||
emit_signal("squeezestart", controller_id);
|
||||
break;
|
||||
|
||||
case WEBXR_INPUT_EVENT_SQUEEZEEND:
|
||||
emit_signal("squeezeend", controller_id);
|
||||
break;
|
||||
|
||||
case WEBXR_INPUT_EVENT_SQUEEZE:
|
||||
emit_signal("squeeze", controller_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int WebXRInterfaceJS::_get_touch_index(int p_input_source) {
|
||||
int index = 0;
|
||||
for (int i = 0; i < p_input_source; i++) {
|
||||
if (godot_webxr_get_controller_target_ray_mode(i) == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
Vector2 WebXRInterfaceJS::_get_joy_vector_from_axes(int *p_axes) {
|
||||
float x_axis = 0.0;
|
||||
float y_axis = 0.0;
|
||||
|
||||
if (p_axes[0] >= 2) {
|
||||
x_axis = *((float *)p_axes + 1);
|
||||
y_axis = *((float *)p_axes + 2);
|
||||
}
|
||||
|
||||
return Vector2(x_axis, y_axis);
|
||||
}
|
||||
|
||||
Vector2 WebXRInterfaceJS::_get_screen_position_from_joy_vector(const Vector2 &p_joy_vector) {
|
||||
// Invert the y-axis.
|
||||
Vector2 position_percentage((p_joy_vector.x + 1.0f) / 2.0f, ((-p_joy_vector.y) + 1.0f) / 2.0f);
|
||||
Vector2 position = get_render_targetsize() * position_percentage;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
void WebXRInterfaceJS::notification(int p_what) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
WebXRInterfaceJS::WebXRInterfaceJS() {
|
||||
initialized = false;
|
||||
session_mode = "inline";
|
||||
requested_reference_space_types = "local";
|
||||
};
|
||||
|
||||
WebXRInterfaceJS::~WebXRInterfaceJS() {
|
||||
// and make sure we cleanup if we haven't already
|
||||
if (initialized) {
|
||||
uninitialize();
|
||||
};
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
@ -1,109 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* webxr_interface_js.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef WEBXR_INTERFACE_JS_H
|
||||
#define WEBXR_INTERFACE_JS_H
|
||||
|
||||
#ifdef JAVASCRIPT_ENABLED
|
||||
|
||||
#include "webxr_interface.h"
|
||||
|
||||
/**
|
||||
@author David Snopek <david.snopek@snopekgames.com>
|
||||
|
||||
The WebXR interface is a VR/AR interface that can be used on the web.
|
||||
*/
|
||||
|
||||
class WebXRInterfaceJS : public WebXRInterface {
|
||||
GDCLASS(WebXRInterfaceJS, WebXRInterface);
|
||||
|
||||
private:
|
||||
bool initialized;
|
||||
|
||||
String session_mode;
|
||||
String required_features;
|
||||
String optional_features;
|
||||
String requested_reference_space_types;
|
||||
String reference_space_type;
|
||||
|
||||
bool controllers_state[2];
|
||||
bool touching[5];
|
||||
Size2 render_targetsize;
|
||||
|
||||
Transform _js_matrix_to_transform(float *p_js_matrix);
|
||||
void _update_tracker(int p_controller_id);
|
||||
|
||||
Vector2 _get_joy_vector_from_axes(int *p_axes);
|
||||
int _get_touch_index(int p_input_source);
|
||||
Vector2 _get_screen_position_from_joy_vector(const Vector2 &p_joy_vector);
|
||||
|
||||
public:
|
||||
virtual void is_session_supported(const String &p_session_mode);
|
||||
virtual void set_session_mode(String p_session_mode);
|
||||
virtual String get_session_mode() const;
|
||||
virtual void set_required_features(String p_required_features);
|
||||
virtual String get_required_features() const;
|
||||
virtual void set_optional_features(String p_optional_features);
|
||||
virtual String get_optional_features() const;
|
||||
virtual void set_requested_reference_space_types(String p_requested_reference_space_types);
|
||||
virtual String get_requested_reference_space_types() const;
|
||||
void _set_reference_space_type(String p_reference_space_type);
|
||||
virtual String get_reference_space_type() const;
|
||||
virtual Ref<ARVRPositionalTracker> get_controller(int p_controller_id) const;
|
||||
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const;
|
||||
virtual String get_visibility_state() const;
|
||||
virtual PoolVector3Array get_bounds_geometry() const;
|
||||
|
||||
virtual StringName get_name() const;
|
||||
virtual int get_capabilities() const;
|
||||
|
||||
virtual bool is_initialized() const;
|
||||
virtual bool initialize();
|
||||
virtual void uninitialize();
|
||||
|
||||
virtual Size2 get_render_targetsize();
|
||||
virtual bool is_stereo();
|
||||
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
|
||||
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
|
||||
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
|
||||
|
||||
virtual void process();
|
||||
virtual void notification(int p_what);
|
||||
|
||||
void _on_controller_changed();
|
||||
void _on_input_event(int p_event_type, int p_input_source);
|
||||
|
||||
WebXRInterfaceJS();
|
||||
~WebXRInterfaceJS();
|
||||
};
|
||||
|
||||
#endif // JAVASCRIPT_ENABLED
|
||||
|
||||
#endif // WEBXR_INTERFACE_JS_H
|
Loading…
Reference in New Issue
Block a user