UNPKG

@photo-sphere-viewer/cubemap-video-adapter

Version:
1 lines 16.6 kB
{"version":3,"sources":["src/index.ts","src/CubemapVideoAdapter.ts","../shared/AbstractVideoAdapter.ts","../shared/video-utils.ts","src/shaders/equiangular.fragment.glsl","src/shaders/equiangular.vertex.glsl"],"sourcesContent":["export { CubemapVideoAdapter } from './CubemapVideoAdapter';\nexport * from './model';\n","import type { AdapterConstructor, TextureData, Viewer } from '@photo-sphere-viewer/core';\nimport { CONSTANTS, utils } from '@photo-sphere-viewer/core';\nimport { BoxGeometry, BufferAttribute, Mesh, ShaderMaterial, Texture, Vector2, VideoTexture } from 'three';\nimport { AbstractVideoAdapter } from '../../shared/AbstractVideoAdapter';\nimport { CubemapVideoAdapterConfig, CubemapVideoData, CubemapVideoPanorama } from './model';\nimport equiangularFragment from './shaders/equiangular.fragment.glsl';\nimport equiangularVertex from './shaders/equiangular.vertex.glsl';\n\ntype CubemapVideoMesh = Mesh<BoxGeometry, ShaderMaterial>;\ntype CubemapVideoTextureData = TextureData<VideoTexture, CubemapVideoPanorama, CubemapVideoData>;\n\ntype ShaderUniforms = {\n map: { value: Texture };\n equiangular: { value: boolean };\n contCorrect: { value: number };\n faceWH: { value: Vector2 };\n vidWH: { value: Vector2 };\n};\n\nconst getConfig = utils.getConfigParser<CubemapVideoAdapterConfig>({\n autoplay: false,\n muted: false,\n});\n\n/**\n * Adapter for cubemap videos\n */\nexport class CubemapVideoAdapter extends AbstractVideoAdapter<CubemapVideoPanorama, CubemapVideoData, CubemapVideoMesh> {\n static override readonly id = 'cubemap-video';\n static override readonly VERSION = PKG_VERSION;\n\n protected override readonly config: CubemapVideoAdapterConfig;\n\n static withConfig(config: CubemapVideoAdapterConfig): [AdapterConstructor, any] {\n return [CubemapVideoAdapter, config];\n }\n\n constructor(viewer: Viewer, config: CubemapVideoAdapterConfig) {\n super(viewer);\n\n this.config = getConfig(config);\n }\n\n override async loadTexture(panorama: CubemapVideoPanorama): Promise<CubemapVideoTextureData> {\n const { texture } = await super.loadTexture(panorama);\n\n const panoData: CubemapVideoData = {\n isCubemap: true,\n equiangular: panorama.equiangular ?? true,\n };\n\n return { panorama, texture, panoData };\n }\n\n createMesh(panoData: CubemapVideoData): CubemapVideoMesh {\n const cubeSize = CONSTANTS.SPHERE_RADIUS * 2;\n const geometry = new BoxGeometry(cubeSize, cubeSize, cubeSize).scale(1, 1, -1).toNonIndexed() as BoxGeometry;\n this.__setUVs(geometry);\n\n const material = new ShaderMaterial({\n uniforms: {\n map: { value: null },\n equiangular: { value: panoData.equiangular },\n contCorrect: { value: 1 },\n faceWH: { value: new Vector2(1 / 3, 1 / 2) },\n vidWH: { value: new Vector2(1, 1) },\n } satisfies ShaderUniforms,\n vertexShader: equiangularVertex,\n fragmentShader: equiangularFragment,\n depthTest: false,\n depthWrite: false,\n });\n\n return new Mesh(geometry, material);\n }\n\n setTexture(mesh: CubemapVideoMesh, { texture }: CubemapVideoTextureData) {\n const video = texture.image as HTMLVideoElement;\n const uniforms = mesh.material.uniforms as ShaderUniforms;\n\n uniforms.map.value = texture;\n uniforms.vidWH.value.set(video.videoWidth, video.videoHeight);\n\n this.switchVideo(texture);\n }\n\n private __setUVs(geometry: BoxGeometry) {\n geometry.clearGroups();\n\n const uvs = geometry.getAttribute('uv') as BufferAttribute;\n\n /*\n Structure of a frame\n\n 1 +---------+---------+---------+\n | | | |\n | Left | Front | Right |\n | | | |\n 1/2 +---------+---------+---------+\n | | | |\n | Bottom | Back | Top |\n | | | |\n 0 +---------+---------+---------+\n 0 1/3 2/3 1\n\n Bottom, Back and Top are rotated 90° clockwise\n */\n\n // columns\n const a = 0;\n const b = 1 / 3;\n const c = 2 / 3;\n const d = 1;\n\n // lines\n const A = 1;\n const B = 1 / 2;\n const C = 0;\n\n // left\n uvs.setXY(0, a, A);\n uvs.setXY(1, a, B);\n uvs.setXY(2, b, A);\n uvs.setXY(3, a, B);\n uvs.setXY(4, b, B);\n uvs.setXY(5, b, A);\n\n // right\n uvs.setXY(6, c, A);\n uvs.setXY(7, c, B);\n uvs.setXY(8, d, A);\n uvs.setXY(9, c, B);\n uvs.setXY(10, d, B);\n uvs.setXY(11, d, A);\n\n // top\n uvs.setXY(12, d, B);\n uvs.setXY(13, c, B);\n uvs.setXY(14, d, C);\n uvs.setXY(15, c, B);\n uvs.setXY(16, c, C);\n uvs.setXY(17, d, C);\n\n // bottom\n uvs.setXY(18, b, B);\n uvs.setXY(19, a, B);\n uvs.setXY(20, b, C);\n uvs.setXY(21, a, B);\n uvs.setXY(22, a, C);\n uvs.setXY(23, b, C);\n\n // back\n uvs.setXY(24, c, B);\n uvs.setXY(25, b, B);\n uvs.setXY(26, c, C);\n uvs.setXY(27, b, B);\n uvs.setXY(28, b, C);\n uvs.setXY(29, c, C);\n\n // front\n uvs.setXY(30, b, A);\n uvs.setXY(31, b, B);\n uvs.setXY(32, c, A);\n uvs.setXY(33, b, B);\n uvs.setXY(34, c, B);\n uvs.setXY(35, c, A);\n }\n}\n","import type { TextureData, Viewer } from '@photo-sphere-viewer/core';\nimport { AbstractAdapter, PSVError } from '@photo-sphere-viewer/core';\nimport { BufferGeometry, Material, Mesh, VideoTexture } from 'three';\nimport { createVideo } from './video-utils';\n\nexport type AbstractVideoPanorama = {\n source: string | MediaStream | HTMLVideoElement;\n};\n\nexport type AbstractVideoAdapterConfig = {\n /**\n * automatically start the video\n * @default false\n */\n autoplay?: boolean;\n /**\n * initially mute the video\n * @default false\n */\n muted?: boolean;\n};\n\ntype AbstractVideoMesh = Mesh<BufferGeometry, Material>;\ntype AbstractVideoTextureData = TextureData<VideoTexture>;\n\n/**\n * Base video adapters class\n */\nexport abstract class AbstractVideoAdapter<\n TPanorama extends AbstractVideoPanorama,\n TData,\n TMesh extends AbstractVideoMesh,\n> extends AbstractAdapter<TPanorama, TData, VideoTexture, TMesh> {\n static override readonly supportsDownload = false;\n\n protected abstract readonly config: AbstractVideoAdapterConfig;\n\n private video: HTMLVideoElement;\n\n constructor(viewer: Viewer) {\n super(viewer);\n }\n\n override init() {\n super.init();\n\n this.viewer.needsContinuousUpdate(true);\n }\n\n override destroy() {\n this.__removeVideo();\n\n super.destroy();\n }\n\n override supportsPreload(): boolean {\n return false;\n }\n\n override supportsTransition(): boolean {\n return false;\n }\n\n async loadTexture(panorama: AbstractVideoPanorama): Promise<AbstractVideoTextureData> {\n if (typeof panorama !== 'object' || !panorama.source) {\n return Promise.reject(new PSVError('Invalid panorama configuration, are you using the right adapter?'));\n }\n\n if (!this.viewer.getPlugin('video')) {\n return Promise.reject(new PSVError('Video adapters require VideoPlugin to be loaded too.'));\n }\n\n const video = panorama.source instanceof HTMLVideoElement\n ? panorama.source\n : createVideo({\n src: panorama.source,\n withCredentials: this.viewer.config.withCredentials(panorama.source as any),\n muted: true,\n autoplay: false,\n });\n\n await this.__videoLoadPromise(video);\n\n const texture = new VideoTexture(video);\n return { panorama, texture };\n }\n\n protected switchVideo(texture: VideoTexture) {\n let currentTime;\n let duration;\n let paused = !this.config.autoplay;\n let muted = this.config.muted;\n let volume = 1;\n if (this.video) {\n ({ currentTime, duration, paused, muted, volume } = this.video);\n }\n\n this.__removeVideo();\n this.video = texture.image;\n\n // keep current time when switching resolution\n if (this.video.duration === duration) {\n this.video.currentTime = currentTime;\n }\n\n // keep volume\n this.video.muted = muted;\n this.video.volume = volume;\n\n // play\n if (!paused) {\n this.video.play();\n }\n }\n\n setTextureOpacity() {\n // noop\n }\n\n disposeTexture({ texture }: AbstractVideoTextureData) {\n texture.dispose();\n }\n\n disposeMesh(mesh: AbstractVideoMesh) {\n mesh.geometry.dispose();\n mesh.material.dispose();\n }\n\n private __removeVideo() {\n if (this.video) {\n this.video.pause();\n this.video.remove();\n delete this.video;\n }\n }\n\n private __videoLoadPromise(video: HTMLVideoElement): Promise<void> {\n return new Promise((resolve, reject) => {\n const onLoaded = () => {\n if (this.video && video.duration === this.video.duration) {\n video.currentTime = this.video.currentTime;\n }\n resolve();\n video.removeEventListener('loadedmetadata', onLoaded);\n };\n\n const onError = (err: ErrorEvent) => {\n reject(err);\n video.removeEventListener('error', onError);\n };\n\n video.addEventListener('loadedmetadata', onLoaded);\n video.addEventListener('error', onError);\n });\n }\n}\n","/**\n * Create a standard video element\n */\nexport function createVideo({\n src,\n withCredentials,\n muted,\n autoplay,\n}: {\n src: string | MediaStream;\n withCredentials: boolean;\n muted: boolean;\n autoplay: boolean;\n}): HTMLVideoElement {\n const video = document.createElement('video');\n video.crossOrigin = withCredentials ? 'use-credentials' : 'anonymous';\n video.loop = true;\n video.playsInline = true;\n video.autoplay = autoplay;\n video.muted = muted;\n video.preload = 'metadata';\n if (src instanceof MediaStream) {\n video.srcObject = src;\n } else {\n video.src = src;\n }\n return video;\n}\n","// shamelessly copied from https://github.com/videojs/videojs-vr/blob/main/src/plugin.js\n\nvarying vec2 vUv;\nuniform sampler2D map;\nuniform bool equiangular;\nuniform float contCorrect;\nuniform vec2 faceWH;\nuniform vec2 vidWH;\n\nconst float PI = 3.1415926535897932384626433832795;\n\nvoid main() {\n vec2 corner = vUv - mod(vUv, faceWH) + vec2(0, contCorrect / vidWH.y);\n vec2 faceWHadj = faceWH - vec2(0, contCorrect * 2. / vidWH.y);\n vec2 p = (vUv - corner) / faceWHadj - .5;\n vec2 q = equiangular ? 2. / PI * atan(2. * p) + .5 : p + .5;\n vec2 eUv = corner + q * faceWHadj;\n gl_FragColor = texture2D(map, eUv);\n}\n","varying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n"],"mappings":"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","names":["import_core","import_three"]}