123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- /*************************************************************************/
- /* library_godot_webxr.js */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
- /* Copyright (c) 2014-2020 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,
- texture_ids: [null, null],
- textures: [null, 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.pauseAsyncCallbacks();
- Browser.mainLoop.pause();
- window.setTimeout(function () {
- Browser.resumeAsyncCallbacks();
- 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 || !GodotWebXR.frame) {
- 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', 'select', 'selectend', 'squeezestart', 'squeeze', 'squeezeend'].forEach((input_event) => {
- session.addEventListener(input_event, function (evt) {
- const c_str = GodotRuntime.allocString(input_event);
- oninputevent(c_str, GodotWebXR.getControllerId(evt.inputSource));
- GodotRuntime.free(c_str);
- });
- });
- 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) => { });
- }
- // Clean-up the textures we allocated for each view.
- const gl = GodotWebXR.gl;
- for (let i = 0; i < GodotWebXR.textures.length; i++) {
- const texture = GodotWebXR.textures[i];
- if (texture !== null) {
- gl.deleteTexture(texture);
- }
- GodotWebXR.textures[i] = null;
- GodotWebXR.texture_ids[i] = null;
- }
- 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_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_get_external_texture_for_eye__proxy: 'sync',
- godot_webxr_get_external_texture_for_eye__sig: 'ii',
- godot_webxr_get_external_texture_for_eye: function (p_eye) {
- if (!GodotWebXR.session || !GodotWebXR.pose) {
- return 0;
- }
- const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
- if (GodotWebXR.texture_ids[view_index]) {
- return GodotWebXR.texture_ids[view_index];
- }
- const glLayer = GodotWebXR.session.renderState.baseLayer;
- const view = GodotWebXR.pose.views[view_index];
- const viewport = glLayer.getViewport(view);
- const gl = GodotWebXR.gl;
- const texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.width, viewport.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- gl.bindTexture(gl.TEXTURE_2D, null);
- const texture_id = GL.getNewId(GL.textures);
- GL.textures[texture_id] = texture;
- GodotWebXR.textures[view_index] = texture;
- GodotWebXR.texture_ids[view_index] = texture_id;
- return texture_id;
- },
- godot_webxr_commit_for_eye__proxy: 'sync',
- godot_webxr_commit_for_eye__sig: 'vi',
- godot_webxr_commit_for_eye: function (p_eye) {
- 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, GodotWebXR.textures[view_index]);
- // 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++) {
- GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.axes[i], 'float');
- }
- return buf;
- },
- 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);
|