Files
old-allhands-vr/node_modules/webvr-polyfill/src/cardboard-vr-display.js
2017-11-19 15:16:07 +01:00

279 lines
8.9 KiB
JavaScript

/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var CardboardDistorter = require('./cardboard-distorter.js');
var CardboardUI = require('./cardboard-ui.js');
var DeviceInfo = require('./device-info.js');
var Dpdb = require('./dpdb/dpdb.js');
var FusionPoseSensor = require('./sensor-fusion/fusion-pose-sensor.js');
var RotateInstructions = require('./rotate-instructions.js');
var ViewerSelector = require('./viewer-selector.js');
var VRDisplay = require('./base.js').VRDisplay;
var Util = require('./util.js');
var Eye = {
LEFT: 'left',
RIGHT: 'right'
};
/**
* VRDisplay based on mobile device parameters and DeviceMotion APIs.
*/
function CardboardVRDisplay() {
this.displayName = 'Cardboard VRDisplay (webvr-polyfill)';
this.capabilities.hasOrientation = true;
this.capabilities.canPresent = true;
// "Private" members.
this.bufferScale_ = WebVRConfig.BUFFER_SCALE;
this.poseSensor_ = new FusionPoseSensor();
this.distorter_ = null;
this.cardboardUI_ = null;
this.dpdb_ = new Dpdb(true, this.onDeviceParamsUpdated_.bind(this));
this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams());
this.viewerSelector_ = new ViewerSelector();
this.viewerSelector_.on('change', this.onViewerChanged_.bind(this));
// Set the correct initial viewer.
this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
if (!WebVRConfig.ROTATE_INSTRUCTIONS_DISABLED) {
this.rotateInstructions_ = new RotateInstructions();
}
if (Util.isIOS()) {
// Listen for resize events to workaround this awful Safari bug.
window.addEventListener('resize', this.onResize_.bind(this));
}
}
CardboardVRDisplay.prototype = new VRDisplay();
CardboardVRDisplay.prototype.getImmediatePose = function() {
return {
position: this.poseSensor_.getPosition(),
orientation: this.poseSensor_.getOrientation(),
linearVelocity: null,
linearAcceleration: null,
angularVelocity: null,
angularAcceleration: null
};
};
CardboardVRDisplay.prototype.resetPose = function() {
this.poseSensor_.resetPose();
};
CardboardVRDisplay.prototype.getEyeParameters = function(whichEye) {
var offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
var fieldOfView;
// TODO: FoV can be a little expensive to compute. Cache when device params change.
if (whichEye == Eye.LEFT) {
offset[0] *= -1.0;
fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
} else if (whichEye == Eye.RIGHT) {
fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
} else {
console.error('Invalid eye provided: %s', whichEye);
return null;
}
return {
fieldOfView: fieldOfView,
offset: offset,
// TODO: Should be able to provide better values than these.
renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
renderHeight: this.deviceInfo_.device.height * this.bufferScale_,
};
};
CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function(newParams) {
if (Util.isDebug()) {
console.log('DPDB reported that device params were updated.');
}
this.deviceInfo_.updateDeviceParams(newParams);
if (this.distorter_) {
this.distorter_.updateDeviceInfo(this.deviceInfo_);
}
};
CardboardVRDisplay.prototype.updateBounds_ = function () {
if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
}
};
CardboardVRDisplay.prototype.beginPresent_ = function() {
var gl = this.layer_.source.getContext('webgl');
if (!gl)
gl = this.layer_.source.getContext('experimental-webgl');
if (!gl)
gl = this.layer_.source.getContext('webgl2');
if (!gl)
return; // Can't do distortion without a WebGL context.
// Provides a way to opt out of distortion
if (this.layer_.predistorted) {
if (!WebVRConfig.CARDBOARD_UI_DISABLED) {
gl.canvas.width = Util.getScreenWidth() * this.bufferScale_;
gl.canvas.height = Util.getScreenHeight() * this.bufferScale_;
this.cardboardUI_ = new CardboardUI(gl);
}
} else {
// Create a new distorter for the target context
this.distorter_ = new CardboardDistorter(gl);
this.distorter_.updateDeviceInfo(this.deviceInfo_);
this.cardboardUI_ = this.distorter_.cardboardUI;
}
if (this.cardboardUI_) {
this.cardboardUI_.listen(function(e) {
// Options clicked.
this.viewerSelector_.show(this.layer_.source.parentElement);
e.stopPropagation();
e.preventDefault();
}.bind(this), function(e) {
// Back clicked.
this.exitPresent();
e.stopPropagation();
e.preventDefault();
}.bind(this));
}
if (this.rotateInstructions_) {
if (Util.isLandscapeMode() && Util.isMobile()) {
// In landscape mode, temporarily show the "put into Cardboard"
// interstitial. Otherwise, do the default thing.
this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
} else {
this.rotateInstructions_.update();
}
}
// Listen for orientation change events in order to show interstitial.
this.orientationHandler = this.onOrientationChange_.bind(this);
window.addEventListener('orientationchange', this.orientationHandler);
// Listen for present display change events in order to update distorter dimensions
this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
// Fire this event initially, to give geometry-distortion clients the chance
// to do something custom.
this.fireVRDisplayDeviceParamsChange_();
};
CardboardVRDisplay.prototype.endPresent_ = function() {
if (this.distorter_) {
this.distorter_.destroy();
this.distorter_ = null;
}
if (this.cardboardUI_) {
this.cardboardUI_.destroy();
this.cardboardUI_ = null;
}
if (this.rotateInstructions_) {
this.rotateInstructions_.hide();
}
this.viewerSelector_.hide();
window.removeEventListener('orientationchange', this.orientationHandler);
window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
};
CardboardVRDisplay.prototype.submitFrame = function(pose) {
if (this.distorter_) {
this.distorter_.submitFrame();
} else if (this.cardboardUI_ && this.layer_) {
// Hack for predistorted: true.
var canvas = this.layer_.source.getContext('webgl').canvas;
if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
this.cardboardUI_.onResize();
}
this.lastWidth = canvas.width;
this.lastHeight = canvas.height;
// Render the Cardboard UI.
this.cardboardUI_.render();
}
};
CardboardVRDisplay.prototype.onOrientationChange_ = function(e) {
// Hide the viewer selector.
this.viewerSelector_.hide();
// Update the rotate instructions.
if (this.rotateInstructions_) {
this.rotateInstructions_.update();
}
this.onResize_();
};
CardboardVRDisplay.prototype.onResize_ = function(e) {
if (this.layer_) {
var gl = this.layer_.source.getContext('webgl');
// Size the CSS canvas.
// Added padding on right and bottom because iPhone 5 will not
// hide the URL bar unless content is bigger than the screen.
// This will not be visible as long as the container element (e.g. body)
// is set to 'overflow: hidden'.
var cssProperties = [
'position: absolute',
'top: 0',
'left: 0',
'width: ' + Math.max(screen.width, screen.height) + 'px',
'height: ' + Math.min(screen.height, screen.width) + 'px',
'border: 0',
'margin: 0',
'padding: 0 10px 10px 0',
];
gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
Util.safariCssSizeWorkaround(gl.canvas);
}
};
CardboardVRDisplay.prototype.onViewerChanged_ = function(viewer) {
this.deviceInfo_.setViewer(viewer);
if (this.distorter_) {
// Update the distortion appropriately.
this.distorter_.updateDeviceInfo(this.deviceInfo_);
}
// Fire a new event containing viewer and device parameters for clients that
// want to implement their own geometry-based distortion.
this.fireVRDisplayDeviceParamsChange_();
};
CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function() {
var event = new CustomEvent('vrdisplaydeviceparamschange', {
detail: {
vrdisplay: this,
deviceInfo: this.deviceInfo_,
}
});
window.dispatchEvent(event);
};
module.exports = CardboardVRDisplay;