{"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"]}