photo-sphere-viewer
Version:
A JavaScript library to display Photo Sphere panoramas
960 lines (789 loc) • 31.2 kB
JavaScript
/*!
* Photo Sphere Viewer 4.8.1
* @copyright 2014-2015 Jérémy Heleine
* @copyright 2015-2022 Damien "Mistic" Sorel
* @licence MIT (https://opensource.org/licenses/MIT)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three'), require('photo-sphere-viewer')) :
typeof define === 'function' && define.amd ? define(['exports', 'three', 'photo-sphere-viewer'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.PhotoSphereViewer = global.PhotoSphereViewer || {}, global.PhotoSphereViewer.EquirectangularTilesAdapter = {}), global.THREE, global.PhotoSphereViewer));
})(this, (function (exports, three, photoSphereViewer) { 'use strict';
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
/**
* @summary Loading task
* @memberOf PSV.adapters
* @private
*/
var Task = /*#__PURE__*/function () {
/**
* @param {string} id
* @param {number} priority
* @param {function(Task): Promise} fn
*/
function Task(id, priority, fn) {
this.id = id;
this.priority = priority;
this.fn = fn;
this.status = Task.STATUS.PENDING;
}
var _proto = Task.prototype;
_proto.start = function start() {
var _this = this;
this.status = Task.STATUS.RUNNING;
return this.fn(this).then(function () {
_this.status = Task.STATUS.DONE;
}, function () {
_this.status = Task.STATUS.ERROR;
});
};
_proto.cancel = function cancel() {
this.status = Task.STATUS.CANCELLED;
};
_proto.isCancelled = function isCancelled() {
return this.status === Task.STATUS.CANCELLED;
};
return Task;
}();
Task.STATUS = {
DISABLED: -1,
PENDING: 0,
RUNNING: 1,
CANCELLED: 2,
DONE: 3,
ERROR: 4
};
/**
* @summary Loading queue
* @memberOf PSV.adapters
* @private
*/
var Queue = /*#__PURE__*/function () {
/**
* @param {int} concurency
*/
function Queue(concurency) {
if (concurency === void 0) {
concurency = 4;
}
this.concurency = concurency;
this.runningTasks = {};
this.tasks = {};
}
var _proto = Queue.prototype;
_proto.enqueue = function enqueue(task) {
this.tasks[task.id] = task;
};
_proto.clear = function clear() {
Object.values(this.tasks).forEach(function (task) {
return task.cancel();
});
this.tasks = {};
this.runningTasks = {};
};
_proto.setPriority = function setPriority(taskId, priority) {
var task = this.tasks[taskId];
if (task) {
task.priority = priority;
if (task.status === Task.STATUS.DISABLED) {
task.status = Task.STATUS.PENDING;
}
}
};
_proto.disableAllTasks = function disableAllTasks() {
Object.values(this.tasks).forEach(function (task) {
task.status = Task.STATUS.DISABLED;
});
};
_proto.start = function start() {
var _this = this;
if (Object.keys(this.runningTasks).length >= this.concurency) {
return;
}
var nextTask = Object.values(this.tasks).filter(function (task) {
return task.status === Task.STATUS.PENDING;
}).sort(function (a, b) {
return b.priority - a.priority;
}).pop();
if (nextTask) {
this.runningTasks[nextTask.id] = true;
nextTask.start().then(function () {
if (!nextTask.isCancelled()) {
delete _this.tasks[nextTask.id];
delete _this.runningTasks[nextTask.id];
_this.start();
}
});
this.start(); // start tasks until max concurrency is reached
}
};
return Queue;
}();
/**
* @summary Generates an material for errored tiles
* @memberOf PSV.adapters
* @return {external:THREE.MeshBasicMaterial}
* @private
*/
function buildErrorMaterial(width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#333';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = canvas.width / 5 + "px serif";
ctx.fillStyle = '#a22';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('⚠', canvas.width / 2, canvas.height / 2);
var texture = new three.CanvasTexture(canvas);
return new three.MeshBasicMaterial({
map: texture
});
}
/**
* @summary Create the texture for the base image
* @memberOf PSV.adapters
* @param {HTMLImageElement} img
* @param {boolean} blur
* @param {function} getHeight
* @return {external:THREE.Texture}
* @private
*/
function createBaseTexture(img, blur, getHeight) {
if (blur || img.width > photoSphereViewer.SYSTEM.maxTextureWidth) {
var ratio = Math.min(1, photoSphereViewer.SYSTEM.getMaxCanvasWidth() / img.width);
var buffer = document.createElement('canvas');
buffer.width = img.width * ratio;
buffer.height = getHeight(img.width);
var ctx = buffer.getContext('2d');
if (blur) {
ctx.filter = 'blur(1px)';
}
ctx.drawImage(img, 0, 0, buffer.width, buffer.height);
return photoSphereViewer.utils.createTexture(buffer);
}
return photoSphereViewer.utils.createTexture(img);
}
/**
* @callback TileUrl
* @summary Function called to build a tile url
* @memberOf PSV.adapters.EquirectangularTilesAdapter
* @param {int} col
* @param {int} row
* @returns {string}
*/
/**
* @typedef {Object} PSV.adapters.EquirectangularTilesAdapter.Panorama
* @summary Configuration of a tiled panorama
* @property {string} [baseUrl] - low resolution panorama loaded before tiles
* @property {PSV.PanoData | PSV.PanoDataProvider} [basePanoData] - panoData configuration associated to low resolution panorama loaded before tiles
* @property {int} width - complete panorama width (height is always width/2)
* @property {int} cols - number of vertical tiles
* @property {int} rows - number of horizontal tiles
* @property {PSV.adapters.EquirectangularTilesAdapter.TileUrl} tileUrl - function to build a tile url
*/
/**
* @typedef {Object} PSV.adapters.EquirectangularTilesAdapter.Options
* @property {number} [resolution=64] - number of faces of the sphere geometry, higher values may decrease performances
* @property {boolean} [showErrorTile=true] - shows a warning sign on tiles that cannot be loaded
* @property {boolean} [baseBlur=true] - applies a blur to the low resolution panorama
*/
/**
* @typedef {Object} PSV.adapters.EquirectangularTilesAdapter.Tile
* @private
* @property {int} col
* @property {int} row
* @property {float} angle
*/
/* the faces of the top and bottom rows are made of a single triangle (3 vertices)
* all other faces are made of two triangles (6 vertices)
* bellow is the indexing of each face vertices
*
* first row faces:
* ⋀
* /0\
* / \
* / \
* /1 2\
* ¯¯¯¯¯¯¯¯¯
*
* other rows faces:
* _________
* |\1 0|
* |3\ |
* | \ |
* | \ |
* | \ |
* | \2|
* |4 5\|
* ¯¯¯¯¯¯¯¯¯
*
* last row faces:
* _________
* \1 0/
* \ /
* \ /
* \2/
* ⋁
*/
var ATTR_UV = 'uv';
var ATTR_ORIGINAL_UV = 'originaluv';
var ATTR_POSITION = 'position';
function tileId(tile) {
return tile.col + "x" + tile.row;
}
var frustum = new three.Frustum();
var projScreenMatrix = new three.Matrix4();
var vertexPosition = new three.Vector3();
/**
* @summary Adapter for tiled panoramas
* @memberof PSV.adapters
* @extends PSV.adapters.AbstractAdapter
*/
var EquirectangularTilesAdapter = /*#__PURE__*/function (_EquirectangularAdapt) {
_inheritsLoose(EquirectangularTilesAdapter, _EquirectangularAdapt);
/**
* @param {PSV.Viewer} psv
* @param {PSV.adapters.EquirectangularTilesAdapter.Options} options
*/
function EquirectangularTilesAdapter(psv, options) {
var _this;
_this = _EquirectangularAdapt.call(this, psv) || this;
_this.psv.config.useXmpData = false;
/**
* @member {PSV.adapters.EquirectangularTilesAdapter.Options}
* @private
*/
_this.config = _extends({
resolution: 64,
showErrorTile: true,
baseBlur: true
}, options);
if (!three.MathUtils.isPowerOfTwo(_this.config.resolution)) {
throw new photoSphereViewer.PSVError('EquirectangularAdapter resolution must be power of two');
}
_this.SPHERE_SEGMENTS = _this.config.resolution;
_this.SPHERE_HORIZONTAL_SEGMENTS = _this.SPHERE_SEGMENTS / 2;
_this.NB_VERTICES_BY_FACE = 6;
_this.NB_VERTICES_BY_SMALL_FACE = 3;
_this.NB_VERTICES = 2 * _this.SPHERE_SEGMENTS * _this.NB_VERTICES_BY_SMALL_FACE + (_this.SPHERE_HORIZONTAL_SEGMENTS - 2) * _this.SPHERE_SEGMENTS * _this.NB_VERTICES_BY_FACE;
_this.NB_GROUPS = _this.SPHERE_SEGMENTS * _this.SPHERE_HORIZONTAL_SEGMENTS;
/**
* @member {PSV.adapters.Queue}
* @private
*/
_this.queue = new Queue();
/**
* @type {Object}
* @property {int} colSize - size in pixels of a column
* @property {int} rowSize - size in pixels of a row
* @property {int} facesByCol - number of mesh faces by column
* @property {int} facesByRow - number of mesh faces by row
* @property {Record<string, boolean>} tiles - loaded tiles
* @property {external:THREE.SphereGeometry} geom
* @property {external:THREE.MeshBasicMaterial[]} materials
* @property {external:THREE.MeshBasicMaterial} errorMaterial
* @private
*/
_this.prop = {
colSize: 0,
rowSize: 0,
facesByCol: 0,
facesByRow: 0,
tiles: {},
geom: null,
materials: [],
errorMaterial: null
};
/**
* @member {external:THREE.ImageLoader}
* @private
*/
_this.loader = null;
if (_this.psv.config.requestHeaders) {
photoSphereViewer.utils.logWarn('EquirectangularTilesAdapter fallbacks to file loader because "requestHeaders" where provided. ' + 'Consider removing "requestHeaders" if you experience performances issues.');
} else {
_this.loader = new three.ImageLoader();
if (_this.psv.config.withCredentials) {
_this.loader.setWithCredentials(true);
}
}
_this.psv.on(photoSphereViewer.CONSTANTS.EVENTS.POSITION_UPDATED, _assertThisInitialized(_this));
_this.psv.on(photoSphereViewer.CONSTANTS.EVENTS.ZOOM_UPDATED, _assertThisInitialized(_this));
return _this;
}
/**
* @override
*/
var _proto = EquirectangularTilesAdapter.prototype;
_proto.destroy = function destroy() {
var _this$prop$errorMater, _this$prop$errorMater2, _this$prop$errorMater3;
this.psv.off(photoSphereViewer.CONSTANTS.EVENTS.POSITION_UPDATED, this);
this.psv.off(photoSphereViewer.CONSTANTS.EVENTS.ZOOM_UPDATED, this);
this.__cleanup();
(_this$prop$errorMater = this.prop.errorMaterial) == null ? void 0 : (_this$prop$errorMater2 = _this$prop$errorMater.map) == null ? void 0 : _this$prop$errorMater2.dispose();
(_this$prop$errorMater3 = this.prop.errorMaterial) == null ? void 0 : _this$prop$errorMater3.dispose();
delete this.queue;
delete this.loader;
delete this.prop.geom;
delete this.prop.errorMaterial;
_EquirectangularAdapt.prototype.destroy.call(this);
}
/**
* @private
*/
;
_proto.handleEvent = function handleEvent(e) {
/* eslint-disable */
switch (e.type) {
case photoSphereViewer.CONSTANTS.EVENTS.POSITION_UPDATED:
case photoSphereViewer.CONSTANTS.EVENTS.ZOOM_UPDATED:
this.__refresh();
break;
}
/* eslint-enable */
}
/**
* @summary Clears loading queue, dispose all materials
* @private
*/
;
_proto.__cleanup = function __cleanup() {
this.queue.clear();
this.prop.tiles = {};
this.prop.materials.forEach(function (mat) {
var _mat$map;
mat == null ? void 0 : (_mat$map = mat.map) == null ? void 0 : _mat$map.dispose();
mat == null ? void 0 : mat.dispose();
});
this.prop.materials.length = 0;
}
/**
* @override
*/
;
_proto.supportsTransition = function supportsTransition(panorama) {
return !!panorama.baseUrl;
}
/**
* @override
*/
;
_proto.supportsPreload = function supportsPreload(panorama) {
return !!panorama.baseUrl;
}
/**
* @override
* @param {PSV.adapters.EquirectangularTilesAdapter.Panorama} panorama
* @returns {Promise.<PSV.TextureData>}
*/
;
_proto.loadTexture = function loadTexture(panorama) {
if (typeof panorama !== 'object' || !panorama.width || !panorama.cols || !panorama.rows || !panorama.tileUrl) {
return Promise.reject(new photoSphereViewer.PSVError('Invalid panorama configuration, are you using the right adapter?'));
}
if (panorama.cols > this.SPHERE_SEGMENTS) {
return Promise.reject(new photoSphereViewer.PSVError("Panorama cols must not be greater than " + this.SPHERE_SEGMENTS + "."));
}
if (panorama.rows > this.SPHERE_HORIZONTAL_SEGMENTS) {
return Promise.reject(new photoSphereViewer.PSVError("Panorama rows must not be greater than " + this.SPHERE_HORIZONTAL_SEGMENTS + "."));
}
if (!three.MathUtils.isPowerOfTwo(panorama.cols) || !three.MathUtils.isPowerOfTwo(panorama.rows)) {
return Promise.reject(new photoSphereViewer.PSVError('Panorama cols and rows must be powers of 2.'));
}
var panoData = {
fullWidth: panorama.width,
fullHeight: panorama.width / 2,
croppedWidth: panorama.width,
croppedHeight: panorama.width / 2,
croppedX: 0,
croppedY: 0,
poseHeading: 0,
posePitch: 0,
poseRoll: 0
};
if (panorama.baseUrl) {
return _EquirectangularAdapt.prototype.loadTexture.call(this, panorama.baseUrl, panorama.basePanoData).then(function (textureData) {
return {
panorama: panorama,
texture: textureData.texture,
panoData: panoData
};
});
} else {
return Promise.resolve({
panorama: panorama,
panoData: panoData
});
}
}
/**
* @override
*/
;
_proto.createMesh = function createMesh(scale) {
if (scale === void 0) {
scale = 1;
}
var geometry = new three.SphereGeometry(photoSphereViewer.CONSTANTS.SPHERE_RADIUS * scale, this.SPHERE_SEGMENTS, this.SPHERE_HORIZONTAL_SEGMENTS, -Math.PI / 2).scale(-1, 1, 1).toNonIndexed();
geometry.clearGroups();
var i = 0;
var k = 0; // first row
for (; i < this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE; i += this.NB_VERTICES_BY_SMALL_FACE) {
geometry.addGroup(i, this.NB_VERTICES_BY_SMALL_FACE, k++);
} // second to before last rows
for (; i < this.NB_VERTICES - this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE; i += this.NB_VERTICES_BY_FACE) {
geometry.addGroup(i, this.NB_VERTICES_BY_FACE, k++);
} // last row
for (; i < this.NB_VERTICES; i += this.NB_VERTICES_BY_SMALL_FACE) {
geometry.addGroup(i, this.NB_VERTICES_BY_SMALL_FACE, k++);
}
geometry.setAttribute(ATTR_ORIGINAL_UV, geometry.getAttribute(ATTR_UV).clone());
return new three.Mesh(geometry, []);
}
/**
* @summary Applies the base texture and starts the loading of tiles
* @override
*/
;
_proto.setTexture = function setTexture(mesh, textureData, transition) {
var _this2 = this;
var panorama = textureData.panorama,
texture = textureData.texture;
if (transition) {
this.__setTexture(mesh, texture);
return;
}
this.__cleanup();
this.__setTexture(mesh, texture);
this.prop.materials = mesh.material;
this.prop.geom = mesh.geometry;
this.prop.geom.setAttribute(ATTR_UV, this.prop.geom.getAttribute(ATTR_ORIGINAL_UV).clone());
this.prop.colSize = panorama.width / panorama.cols;
this.prop.rowSize = panorama.width / 2 / panorama.rows;
this.prop.facesByCol = this.SPHERE_SEGMENTS / panorama.cols;
this.prop.facesByRow = this.SPHERE_HORIZONTAL_SEGMENTS / panorama.rows; // this.psv.renderer.scene.add(createWireFrame(this.prop.geom));
setTimeout(function () {
return _this2.__refresh(true);
});
}
/**
* @private
*/
;
_proto.__setTexture = function __setTexture(mesh, texture) {
var material;
if (texture) {
material = new three.MeshBasicMaterial({
map: texture
});
} else {
material = new three.MeshBasicMaterial({
opacity: 0,
transparent: true
});
}
for (var i = 0; i < this.NB_GROUPS; i++) {
mesh.material.push(material);
}
}
/**
* @override
*/
;
_proto.setTextureOpacity = function setTextureOpacity(mesh, opacity) {
mesh.material[0].opacity = opacity;
mesh.material[0].transparent = opacity < 1;
}
/**
* @summary Compute visible tiles and load them
* @param {boolean} [init=false] Indicates initial call
* @private
*/
;
_proto.__refresh = function __refresh(init) {
var _this3 = this;
// eslint-disable-line no-unused-vars
if (!this.prop.geom) {
return;
}
var camera = this.psv.renderer.camera;
camera.updateMatrixWorld();
projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
frustum.setFromProjectionMatrix(projScreenMatrix);
var panorama = this.psv.config.panorama;
var verticesPosition = this.prop.geom.getAttribute(ATTR_POSITION);
var tilesToLoad = [];
for (var col = 0; col < panorama.cols; col++) {
for (var row = 0; row < panorama.rows; row++) {
// for each tile, find the vertices corresponding to the four corners (three for first and last rows)
// if at least one vertex is visible, the tile must be loaded
// for larger tiles we also test the four edges centers and the tile center
var verticesIndex = [];
if (row === 0) {
// bottom-left
var v0 = this.prop.facesByRow === 1 ? col * this.prop.facesByCol * this.NB_VERTICES_BY_SMALL_FACE + 1 : this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE + (this.prop.facesByRow - 2) * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE + col * this.prop.facesByCol * this.NB_VERTICES_BY_FACE + 4; // bottom-right
var v1 = this.prop.facesByRow === 1 ? v0 + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_SMALL_FACE + 1 : v0 + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_FACE + 1; // top (all vertices are equal)
var v2 = 0;
verticesIndex.push(v0, v1, v2);
if (this.prop.facesByCol >= this.SPHERE_SEGMENTS / 8) {
// bottom-center
var v4 = v0 + this.prop.facesByCol / 2 * this.NB_VERTICES_BY_FACE;
verticesIndex.push(v4);
}
if (this.prop.facesByRow >= this.SPHERE_HORIZONTAL_SEGMENTS / 4) {
// left-center
var v6 = v0 - this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE; // right-center
var v7 = v1 - this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE;
verticesIndex.push(v6, v7);
}
} else if (row === panorama.rows - 1) {
// top-left
var _v = this.prop.facesByRow === 1 ? -this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE + row * this.prop.facesByRow * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE + col * this.prop.facesByCol * this.NB_VERTICES_BY_SMALL_FACE + 1 : -this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE + row * this.prop.facesByRow * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE + col * this.prop.facesByCol * this.NB_VERTICES_BY_FACE + 1; // top-right
var _v2 = this.prop.facesByRow === 1 ? _v + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_SMALL_FACE - 1 : _v + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_FACE - 1; // bottom (all vertices are equal)
var _v3 = this.NB_VERTICES - 1;
verticesIndex.push(_v, _v2, _v3);
if (this.prop.facesByCol >= this.SPHERE_SEGMENTS / 8) {
// top-center
var _v4 = _v + this.prop.facesByCol / 2 * this.NB_VERTICES_BY_FACE;
verticesIndex.push(_v4);
}
if (this.prop.facesByRow >= this.SPHERE_HORIZONTAL_SEGMENTS / 4) {
// left-center
var _v5 = _v + this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE; // right-center
var _v6 = _v2 + this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE;
verticesIndex.push(_v5, _v6);
}
} else {
// top-left
var _v7 = -this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_SMALL_FACE + row * this.prop.facesByRow * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE + col * this.prop.facesByCol * this.NB_VERTICES_BY_FACE + 1; // bottom-left
var _v8 = _v7 + (this.prop.facesByRow - 1) * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE + 3; // bottom-right
var _v9 = _v8 + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_FACE + 1; // top-right
var v3 = _v7 + (this.prop.facesByCol - 1) * this.NB_VERTICES_BY_FACE - 1;
verticesIndex.push(_v7, _v8, _v9, v3);
if (this.prop.facesByCol >= this.SPHERE_SEGMENTS / 8) {
// top-center
var _v10 = _v7 + this.prop.facesByCol / 2 * this.NB_VERTICES_BY_FACE; // bottom-center
var v5 = _v8 + this.prop.facesByCol / 2 * this.NB_VERTICES_BY_FACE;
verticesIndex.push(_v10, v5);
}
if (this.prop.facesByRow >= this.SPHERE_HORIZONTAL_SEGMENTS / 4) {
// left-center
var _v11 = _v7 + this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE; // right-center
var _v12 = v3 + this.prop.facesByRow / 2 * this.SPHERE_SEGMENTS * this.NB_VERTICES_BY_FACE;
verticesIndex.push(_v11, _v12);
if (this.prop.facesByCol >= this.SPHERE_SEGMENTS / 8) {
// center-center
var v8 = _v11 + this.prop.facesByCol / 2 * this.NB_VERTICES_BY_FACE;
verticesIndex.push(v8);
}
}
} // if (init && col === 0 && row === 0) {
// verticesIndex.forEach((vertexIdx) => {
// this.psv.renderer.scene.add(createDot(
// verticesPosition.getX(vertexIdx),
// verticesPosition.getY(vertexIdx),
// verticesPosition.getZ(vertexIdx)
// ));
// });
// }
var vertexVisible = verticesIndex.some(function (vertexIdx) {
vertexPosition.set(verticesPosition.getX(vertexIdx), verticesPosition.getY(vertexIdx), verticesPosition.getZ(vertexIdx));
vertexPosition.applyEuler(_this3.psv.renderer.meshContainer.rotation);
return frustum.containsPoint(vertexPosition);
});
if (vertexVisible) {
var angle = vertexPosition.angleTo(this.psv.prop.direction);
if (row === 0 || row === panorama.rows - 1) {
angle *= 2; // lower priority to top and bottom tiles
}
tilesToLoad.push({
col: col,
row: row,
angle: angle
});
}
}
}
this.__loadTiles(tilesToLoad);
}
/**
* @summary Loads tiles and change existing tiles priority
* @param {PSV.adapters.EquirectangularTilesAdapter.Tile[]} tiles
* @private
*/
;
_proto.__loadTiles = function __loadTiles(tiles) {
var _this4 = this;
this.queue.disableAllTasks();
tiles.forEach(function (tile) {
var id = tileId(tile);
if (_this4.prop.tiles[id]) {
_this4.queue.setPriority(id, tile.angle);
} else {
_this4.prop.tiles[id] = true;
_this4.queue.enqueue(new Task(id, tile.angle, function (task) {
return _this4.__loadTile(tile, task);
}));
}
});
this.queue.start();
}
/**
* @summary Loads and draw a tile
* @param {PSV.adapters.EquirectangularTilesAdapter.Tile} tile
* @param {PSV.adapters.Task} task
* @return {Promise}
* @private
*/
;
_proto.__loadTile = function __loadTile(tile, task) {
var _this5 = this;
var panorama = this.psv.config.panorama;
var url = panorama.tileUrl(tile.col, tile.row);
return this.__loadImage(url).then(function (image) {
if (!task.isCancelled()) {
var material = new three.MeshBasicMaterial({
map: photoSphereViewer.utils.createTexture(image)
});
_this5.__swapMaterial(tile.col, tile.row, material);
_this5.psv.needsUpdate();
}
}).catch(function () {
if (!task.isCancelled() && _this5.config.showErrorTile) {
if (!_this5.prop.errorMaterial) {
_this5.prop.errorMaterial = buildErrorMaterial(_this5.prop.colSize, _this5.prop.rowSize);
}
_this5.__swapMaterial(tile.col, tile.row, _this5.prop.errorMaterial);
_this5.psv.needsUpdate();
}
});
}
/**
* @private
*/
;
_proto.__loadImage = function __loadImage(url) {
var _this6 = this;
if (this.loader) {
return new Promise(function (resolve, reject) {
_this6.loader.load(url, resolve, undefined, reject);
});
} else {
return this.psv.textureLoader.loadImage(url);
}
}
/**
* @summary Applies a new texture to the faces
* @param {int} col
* @param {int} row
* @param {external:THREE.MeshBasicMaterial} material
* @private
*/
;
_proto.__swapMaterial = function __swapMaterial(col, row, material) {
var _this7 = this;
var uvs = this.prop.geom.getAttribute(ATTR_UV);
for (var c = 0; c < this.prop.facesByCol; c++) {
var _loop = function _loop(r) {
// position of the face (two triangles of the same square)
var faceCol = col * _this7.prop.facesByCol + c;
var faceRow = row * _this7.prop.facesByRow + r;
var isFirstRow = faceRow === 0;
var isLastRow = faceRow === _this7.SPHERE_HORIZONTAL_SEGMENTS - 1; // first vertex for this face (3 or 6 vertices in total)
var firstVertex = void 0;
if (isFirstRow) {
firstVertex = faceCol * _this7.NB_VERTICES_BY_SMALL_FACE;
} else if (isLastRow) {
firstVertex = _this7.NB_VERTICES - _this7.SPHERE_SEGMENTS * _this7.NB_VERTICES_BY_SMALL_FACE + faceCol * _this7.NB_VERTICES_BY_SMALL_FACE;
} else {
firstVertex = _this7.SPHERE_SEGMENTS * _this7.NB_VERTICES_BY_SMALL_FACE + (faceRow - 1) * _this7.SPHERE_SEGMENTS * _this7.NB_VERTICES_BY_FACE + faceCol * _this7.NB_VERTICES_BY_FACE;
} // swap material
var matIndex = _this7.prop.geom.groups.find(function (g) {
return g.start === firstVertex;
}).materialIndex;
_this7.prop.materials[matIndex] = material; // define new uvs
var top = 1 - r / _this7.prop.facesByRow;
var bottom = 1 - (r + 1) / _this7.prop.facesByRow;
var left = c / _this7.prop.facesByCol;
var right = (c + 1) / _this7.prop.facesByCol;
if (isFirstRow) {
uvs.setXY(firstVertex, (left + right) / 2, top);
uvs.setXY(firstVertex + 1, left, bottom);
uvs.setXY(firstVertex + 2, right, bottom);
} else if (isLastRow) {
uvs.setXY(firstVertex, right, top);
uvs.setXY(firstVertex + 1, left, top);
uvs.setXY(firstVertex + 2, (left + right) / 2, bottom);
} else {
uvs.setXY(firstVertex, right, top);
uvs.setXY(firstVertex + 1, left, top);
uvs.setXY(firstVertex + 2, right, bottom);
uvs.setXY(firstVertex + 3, left, top);
uvs.setXY(firstVertex + 4, left, bottom);
uvs.setXY(firstVertex + 5, right, bottom);
}
};
for (var r = 0; r < this.prop.facesByRow; r++) {
_loop(r);
}
}
uvs.needsUpdate = true;
}
/**
* @summary Create the texture for the base image
* @param {HTMLImageElement} img
* @return {external:THREE.Texture}
* @private
*/
;
_proto.__createBaseTexture = function __createBaseTexture(img) {
if (img.width !== img.height * 2) {
photoSphereViewer.utils.logWarn('Invalid base image, the width should be twice the height');
}
return createBaseTexture(img, this.config.baseBlur, function (w) {
return w / 2;
});
};
return EquirectangularTilesAdapter;
}(photoSphereViewer.EquirectangularAdapter);
EquirectangularTilesAdapter.id = 'equirectangular-tiles';
EquirectangularTilesAdapter.supportsDownload = false;
EquirectangularTilesAdapter.supportsOverlay = false;
exports.EquirectangularTilesAdapter = EquirectangularTilesAdapter;
Object.defineProperty(exports, '__esModule', { value: true });
}));
//# sourceMappingURL=equirectangular-tiles.js.map