blob: 4ceae7d940413d8701f053e857418ae153a723bb [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Add additional setup steps to the object from webvr_e2e.js if it exists.
if (typeof initializationSteps !== 'undefined') {
initializationSteps['magicWindowStarted'] = false;
} else {
// Create here if it doesn't exist so we can access it later without checking
// if it's defined.
var initializationSteps = {};
}
var webglCanvas = document.getElementById('webgl-canvas');
var glAttribs = {
alpha: false,
xrCompatible: true,
};
var gl = null;
var onMagicWindowXRFrameCallback = null;
var onImmersiveXRFrameCallback = null;
var onSessionStartedCallback = null;
var onPoseCallback = null;
var shouldSubmitFrame = true;
var hasPresentedFrame = false;
var arSessionRequestWouldTriggerPermissionPrompt = null;
var sessionTypes = Object.freeze({
IMMERSIVE: 1,
AR: 2,
MAGIC_WINDOW: 3
});
var sessionTypeToRequest = sessionTypes.IMMERSIVE;
var referenceSpaceMap = {
[sessionTypes.IMMERSIVE]: 'local',
[sessionTypes.MAGIC_WINDOW]: 'viewer',
[sessionTypes.AR]: 'viewer'
}
class SessionInfo {
constructor() {
this.session = null;
this.frameOfRef = null;
this.error = null;
}
get currentSession() {
return this.session;
}
get currentRefSpace() {
return this.frameOfRef;
}
set currentSession(session) {
this.session = session;
}
set currentRefSpace(frameOfRef) {
this.frameOfRef = frameOfRef;
}
clearSession() {
this.session = null;
this.frameOfRef = null;
this.error = null;
}
}
var sessionInfos = {}
sessionInfos[sessionTypes.IMMERSIVE] = new SessionInfo();
sessionInfos[sessionTypes.AR] = new SessionInfo();
sessionInfos[sessionTypes.MAGIC_WINDOW] = new SessionInfo();
function getSessionType(session) {
if (session.mode == 'immersive-vr') {
return sessionTypes.IMMERSIVE;
} else if (session.mode == 'immersive-ar') {
return sessionTypes.AR;
} else {
return sessionTypes.MAGIC_WINDOW;
}
}
function onRequestSession() {
switch (sessionTypeToRequest) {
case sessionTypes.IMMERSIVE:
console.info('Requesting immersive VR session');
navigator.xr.requestSession('immersive-vr').then( (session) => {
session.mode = 'immersive-vr';
console.info('Immersive VR session request succeeded');
sessionInfos[sessionTypes.IMMERSIVE].currentSession = session;
onSessionStarted(session);
}, (error) => {
sessionInfos[sessionTypes.IMMERSIVE].error = error;
console.info('Immersive VR session request rejected with: ' + error);
});
break;
case sessionTypes.AR:
console.info('Requesting Immersive AR session');
navigator.xr.requestSession('immersive-ar').then((session) => {
session.mode = 'immersive-ar';
console.info('Immersive AR session request succeeded');
sessionInfos[sessionTypes.AR].currentSession = session;
onSessionStarted(session);
}, (error) => {
sessionInfos[sessionTypes.AR].error = error;
console.info('Immersive AR session request rejected with: ' + error);
});
break;
default:
throw 'Given unsupported WebXR session type enum ' + sessionTypeToRequest;
}
}
function onSessionStarted(session) {
session.addEventListener('end', onSessionEnded);
// Initialize the WebGL context for use with XR if it hasn't been already
if (!gl) {
// Create an offscreen canvas and get its context
let offscreenCanvas = document.createElement('canvas');
gl = offscreenCanvas.getContext('webgl', glAttribs);
if (!gl) {
throw 'Failed to get WebGL context';
}
gl.clearColor(0.0, 1.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
if (onSessionStartedCallback) {
onSessionStartedCallback(session);
}
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
session.requestReferenceSpace(referenceSpaceMap[getSessionType(session)])
.then( (refSpace) => {
sessionInfos[getSessionType(session)].currentRefSpace = refSpace;
session.requestAnimationFrame(onXRFrame);
});
}
function onSessionEnded(event) {
sessionInfos[getSessionType(event.session)].clearSession();
}
function onXRFrame(t, frame) {
let session = frame.session;
session.requestAnimationFrame(onXRFrame);
let refSpace = sessionInfos[getSessionType(session)].currentRefSpace;
let pose = frame.getViewerPose(refSpace);
if (onPoseCallback) {
onPoseCallback(pose);
}
// Exiting the rAF callback without dirtying the GL context is interpreted
// as not submitting a frame
if (!shouldSubmitFrame) {
return;
}
gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer);
// If in an immersive session, set canvas to blue.
// If in an AR session, just draw the camera.
// Otherwise, red.
switch (getSessionType(session)) {
case sessionTypes.IMMERSIVE:
gl.clearColor(0.0, 0.0, 1.0, 1.0);
if (onImmersiveXRFrameCallback) {
onImmersiveXRFrameCallback(session, frame, gl);
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
break;
case sessionTypes.AR:
// Do nothing for now
break;
default:
if (onMagicWindowXRFrameCallback) {
onMagicWindowXRFrameCallback(session, frame);
}
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
hasPresentedFrame = true;
}
function requestMagicWindowSession() {
// Set up an inline session (magic window) drawing into the full screen canvas
// on the page
let ctx = webglCanvas.getContext('xrpresent');
navigator.xr.requestSession('inline')
.then((session) => {
session.mode = 'inline';
session.updateRenderState({
outputContext: ctx
});
onSessionStarted(session);
})
.then( () => {
initializationSteps['magicWindowStarted'] = true;
});
}
if (navigator.xr) {
// WebXR for VR tests want an inline session to be automatically
// created on page load to reduce the amount of boilerplate code necessary.
// However, doing so during AR tests currently fails due to AR sessions
// always requiring a user gesture. So, allow a page to set a variable
// before loading this JavaScript file if they wish to skip the automatic
// inline session creation.
if (typeof shouldAutoCreateNonImmersiveSession === 'undefined'
|| shouldAutoCreateNonImmersiveSession === true) {
// Separate if statement to keep the logic around setting initialization
// steps cleaner.
if (typeof shouldDeferNonImmersiveSessionCreation === 'undefined'
|| shouldDeferNonImmersiveSessionCreation === false) {
requestMagicWindowSession();
}
} else {
initializationSteps['magicWindowStarted'] = true;
}
} else {
initializationSteps['magicWindowStarted'] = true;
}
webglCanvas.onclick = onRequestSession;