From 5214a16b9aa625463d5b6f2a315b5da8f8977ca5 Mon Sep 17 00:00:00 2001 From: machenmusik Date: Thu, 24 Aug 2017 17:52:12 -0400 Subject: [PATCH] extend PR #2985 (moved canvas init) to also solve issue #2967 (vr2vr traversal in Oculus Browser) (#2991) * Moves canvas initialization logic from a component to the scene. This handle the case when calling enterVR before the renderer is initialized and also moves the canvas and renderer initialization before assets load (it's not a component anymore). This is a prequesite for a loading screen / spinner * add vrdisplayactivate handler earlier than previously, as Oculus Browser fires it quite early on * remove redundant vrdisplayactivate listener in a-scene; improve comments --- src/components/index.js | 1 - src/components/scene/canvas.js | 43 ------------------- src/core/scene/a-scene.js | 59 +++++++++++++++++++++++---- src/index.js | 8 ++++ tests/components/scene/canvas.test.js | 13 ------ tests/core/scene/a-scene.test.js | 12 +++++- 6 files changed, 69 insertions(+), 67 deletions(-) delete mode 100644 src/components/scene/canvas.js delete mode 100644 tests/components/scene/canvas.test.js diff --git a/src/components/index.js b/src/components/index.js index 55a0633100c..00119985529 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -26,7 +26,6 @@ require('./visible'); require('./vive-controls'); require('./wasd-controls'); -require('./scene/canvas'); require('./scene/debug'); require('./scene/embedded'); require('./scene/inspector'); diff --git a/src/components/scene/canvas.js b/src/components/scene/canvas.js deleted file mode 100644 index 3eb2e5fbbbf..00000000000 --- a/src/components/scene/canvas.js +++ /dev/null @@ -1,43 +0,0 @@ -var bind = require('../../utils/bind'); -var registerComponent = require('../../core/component').registerComponent; - -module.exports.Component = registerComponent('canvas', { - init: function () { - var canvasEl; - var sceneEl = this.el; - - canvasEl = document.createElement('canvas'); - canvasEl.classList.add('a-canvas'); - // Mark canvas as provided/injected by A-Frame. - canvasEl.dataset.aframeCanvas = true; - sceneEl.appendChild(canvasEl); - - document.addEventListener('fullscreenchange', onFullScreenChange); - document.addEventListener('mozfullscreenchange', onFullScreenChange); - document.addEventListener('webkitfullscreenchange', onFullScreenChange); - - // Prevent overscroll on mobile. - canvasEl.addEventListener('touchmove', function (event) { - event.preventDefault(); - }); - - // Set canvas on scene. - sceneEl.canvas = canvasEl; - sceneEl.emit('render-target-loaded', {target: canvasEl}); - - // For unknown reasons a syncrhonous resize does not work on desktop when - // entering/exiting fullscreen. - setTimeout(bind(sceneEl.resize, sceneEl), 0); - - function onFullScreenChange () { - var fullscreenEl = - document.fullscreenElement || - document.mozFullScreenElement || - document.webkitFullscreenElement; - // No fullscren element === exit fullscreen - if (!fullscreenEl) { sceneEl.exitVR(); } - document.activeElement.blur(); - document.body.focus(); - } - } -}); diff --git a/src/core/scene/a-scene.js b/src/core/scene/a-scene.js index 93c725c8241..5ca5ddc85c0 100644 --- a/src/core/scene/a-scene.js +++ b/src/core/scene/a-scene.js @@ -39,7 +39,6 @@ module.exports.AScene = registerElement('a-scene', { prototype: Object.create(AEntity.prototype, { defaultComponents: { value: { - 'canvas': '', 'inspector': '', 'keyboard-shortcuts': '', 'screenshot': '', @@ -68,10 +67,9 @@ module.exports.AScene = registerElement('a-scene', { this.isPlaying = false; this.originalHTML = this.innerHTML; this.renderTarget = null; - this.addEventListener('render-target-loaded', function () { - this.setupRenderer(); - this.resize(); - }); + this.setupCanvas(); + this.setupRenderer(); + this.resize(); this.addFullScreenStyles(); initPostMessageAPI(this); }, @@ -122,8 +120,8 @@ module.exports.AScene = registerElement('a-scene', { this.exitVRBound = function () { self.exitVR(); }; this.exitVRTrueBound = function () { self.exitVR(true); }; - // Enter VR on `vrdisplayactivate` (e.g. putting on Rift headset). - window.addEventListener('vrdisplayactivate', this.enterVRBound); + // There is already a listener for `vrdisplayactivate` (e.g. putting on Rift headset), + // since that event is also used for in-VR traversal, much earlier in the lifecycle. // Exit VR on `vrdisplaydeactivate` (e.g. taking off Rift headset). window.addEventListener('vrdisplaydeactivate', this.exitVRBound); @@ -224,13 +222,14 @@ module.exports.AScene = registerElement('a-scene', { enterVR: { value: function (fromExternal) { var self = this; + var effect = this.effect; // Don't enter VR if already in VR. if (this.is('vr-mode')) { return Promise.resolve('Already in VR.'); } // Enter VR via WebVR API. if (!fromExternal && (this.checkHeadsetConnected() || this.isMobile)) { - return this.effect.requestPresent().then(enterVRSuccess, enterVRFailure); + return effect && effect.requestPresent().then(enterVRSuccess, enterVRFailure) || Promise.reject(new Error('VREffect not initialized')); } // Either entered VR already via WebVR API or VR not supported. @@ -431,7 +430,9 @@ module.exports.AScene = registerElement('a-scene', { setupRenderer: { value: function () { - var renderer = this.renderer = new THREE.WebGLRenderer({ + var renderer; + + renderer = this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas, antialias: shouldAntiAlias(this), alpha: true @@ -449,6 +450,46 @@ module.exports.AScene = registerElement('a-scene', { writable: window.debug }, + setupCanvas: { + value: function () { + var canvasEl; + var sceneEl = this; + + canvasEl = document.createElement('canvas'); + canvasEl.classList.add('a-canvas'); + // Mark canvas as provided/injected by A-Frame. + canvasEl.dataset.aframeCanvas = true; + sceneEl.appendChild(canvasEl); + + document.addEventListener('fullscreenchange', onFullScreenChange); + document.addEventListener('mozfullscreenchange', onFullScreenChange); + document.addEventListener('webkitfullscreenchange', onFullScreenChange); + + // Prevent overscroll on mobile. + canvasEl.addEventListener('touchmove', function (event) { + event.preventDefault(); + }); + + // Set canvas on scene. + sceneEl.canvas = canvasEl; + sceneEl.emit('render-target-loaded', {target: canvasEl}); + // For unknown reasons a syncrhonous resize does not work on desktop when + // entering/exiting fullscreen. + setTimeout(bind(sceneEl.resize, sceneEl), 0); + + function onFullScreenChange () { + var fullscreenEl = + document.fullscreenElement || + document.mozFullScreenElement || + document.webkitFullscreenElement; + // No fullscren element === exit fullscreen + if (!fullscreenEl) { sceneEl.exitVR(); } + document.activeElement.blur(); + document.body.focus(); + } + } + }, + /** * Handler attached to elements to help scene know when to kick off. * Scene waits for all entities to load. diff --git a/src/index.js b/src/index.js index 65a7818dbf9..4869895262d 100644 --- a/src/index.js +++ b/src/index.js @@ -113,3 +113,11 @@ module.exports = window.AFRAME = { utils: utils, version: pkg.version }; + +// Enter VR on `vrdisplayactivate`, to handle in-VR traversal much earlier in the lifecycle. +// This event may also fire in other circumstances (e.g. putting on the Rift headset). +window.addEventListener('vrdisplayactivate', function (evt) { + if (window.AFRAME.scenes.length > 0) { + window.AFRAME.scenes[0].enterVR(); + } +}); diff --git a/tests/components/scene/canvas.test.js b/tests/components/scene/canvas.test.js deleted file mode 100644 index fb9aa1c51e7..00000000000 --- a/tests/components/scene/canvas.test.js +++ /dev/null @@ -1,13 +0,0 @@ - /* global assert, process, suite, test */ - -suite('canvas', function () { - test('adds canvas to a-scene element', function (done) { - var el = this.sceneEl = document.createElement('a-scene'); - document.body.appendChild(el); - el.addEventListener('loaded', function () { - el.setAttribute('canvas', ''); - assert.ok(el.querySelector('canvas')); - done(); - }); - }); -}); diff --git a/tests/core/scene/a-scene.test.js b/tests/core/scene/a-scene.test.js index e217dc7ca3e..160ebddd835 100644 --- a/tests/core/scene/a-scene.test.js +++ b/tests/core/scene/a-scene.test.js @@ -385,7 +385,7 @@ suite('a-scene (without renderer)', function () { var sceneEl = this.el; sceneEl.innerHTML = 'NEW'; sceneEl.reload(); - assert.equal(sceneEl.innerHTML, ''); + assert.equal(sceneEl.innerHTML, ''); }); test('reloads the scene and pauses', function () { @@ -605,6 +605,16 @@ suite('scenes', function () { }); }); +suite('setupCanvas', function () { + test('adds canvas to a-scene element', function () { + var el = this.sceneEl = document.createElement('a-scene'); + el.canvas = undefined; + assert.notOk(el.canvas); + el.setupCanvas(); + assert.ok(el.canvas); + }); +}); + suite('shouldAntiAlias', function () { var sceneEl;