forked from EXT/VR180-Web-Player
Folder organisation
This commit is contained in:
265
src/vr180player/modes/two-d-mode.ts
Normal file
265
src/vr180player/modes/two-d-mode.ts
Normal file
@@ -0,0 +1,265 @@
|
||||
import type { ProjectionMode } from '../config.js';
|
||||
import type { FallbackCameraControls } from './fallback-camera-controls.js';
|
||||
import {
|
||||
hideRendererCanvas,
|
||||
resizeFallbackRenderer,
|
||||
showFallbackCanvas
|
||||
} from '../rendering/renderer-lifecycle.js';
|
||||
import { TwoDControlPanel } from '../dom/two-d-control-panel.js';
|
||||
|
||||
type TwoDModeCallbacks = {
|
||||
createMediaTexture: () => any;
|
||||
forward: () => void;
|
||||
positionPlaneForPresentation: (isFallback2D?: boolean) => void;
|
||||
rewind: () => void;
|
||||
seekToProgress: (progress: number) => void;
|
||||
showActiveContentMesh: () => void;
|
||||
toggleMute: () => void;
|
||||
togglePlayPause: () => void;
|
||||
};
|
||||
|
||||
type TwoDModeOptions = {
|
||||
callbacks: TwoDModeCallbacks;
|
||||
fullscreenTarget: HTMLElement;
|
||||
getActiveContentMesh: () => any;
|
||||
getCamera: () => any;
|
||||
getCameraControls: () => FallbackCameraControls | undefined;
|
||||
getMaterial: () => any;
|
||||
getRenderer: () => any;
|
||||
getScene: () => any;
|
||||
getVideo: () => HTMLVideoElement | undefined;
|
||||
playerContainer: HTMLElement;
|
||||
projectionMode: ProjectionMode;
|
||||
title: string;
|
||||
};
|
||||
|
||||
const FULLSCREEN_RESIZE_DELAY = 100;
|
||||
|
||||
export class TwoDMode {
|
||||
private readonly callbacks: TwoDModeCallbacks;
|
||||
private readonly controls: TwoDControlPanel;
|
||||
private readonly fullscreenTarget: HTMLElement;
|
||||
private readonly getActiveContentMesh: () => any;
|
||||
private readonly getCamera: () => any;
|
||||
private readonly getCameraControls: () => FallbackCameraControls | undefined;
|
||||
private readonly getMaterial: () => any;
|
||||
private readonly getRenderer: () => any;
|
||||
private readonly getScene: () => any;
|
||||
private readonly getVideo: () => HTMLVideoElement | undefined;
|
||||
private readonly playerContainer: HTMLElement;
|
||||
private readonly projectionMode: ProjectionMode;
|
||||
private active = false;
|
||||
|
||||
constructor(options: TwoDModeOptions) {
|
||||
this.callbacks = options.callbacks;
|
||||
this.fullscreenTarget = options.fullscreenTarget;
|
||||
this.getActiveContentMesh = options.getActiveContentMesh;
|
||||
this.getCamera = options.getCamera;
|
||||
this.getCameraControls = options.getCameraControls;
|
||||
this.getMaterial = options.getMaterial;
|
||||
this.getRenderer = options.getRenderer;
|
||||
this.getScene = options.getScene;
|
||||
this.getVideo = options.getVideo;
|
||||
this.playerContainer = options.playerContainer;
|
||||
this.projectionMode = options.projectionMode;
|
||||
|
||||
this.controls = new TwoDControlPanel({
|
||||
callbacks: {
|
||||
onForward: () => {
|
||||
this.callbacks.forward();
|
||||
},
|
||||
onMute: () => {
|
||||
this.callbacks.toggleMute();
|
||||
},
|
||||
onPlayPause: this.callbacks.togglePlayPause,
|
||||
onRewind: () => {
|
||||
this.callbacks.rewind();
|
||||
},
|
||||
onSeek: (progress) => {
|
||||
this.callbacks.seekToProgress(progress);
|
||||
}
|
||||
},
|
||||
fullscreenTarget: this.fullscreenTarget,
|
||||
getIsActive: () => this.active,
|
||||
playerContainer: this.playerContainer,
|
||||
title: options.title
|
||||
});
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
const video = this.getVideo();
|
||||
const renderer = this.getRenderer();
|
||||
const camera = this.getCamera();
|
||||
|
||||
if (!video || !renderer || !camera) {
|
||||
console.error("Required components not available for 2D mode");
|
||||
return;
|
||||
}
|
||||
|
||||
this.active = true;
|
||||
this.resizeCanvasFor2D(renderer, camera);
|
||||
|
||||
const canvas = showFallbackCanvas(renderer);
|
||||
video.style.display = 'none';
|
||||
|
||||
const mediaTexture = this.callbacks.createMediaTexture();
|
||||
this.callbacks.positionPlaneForPresentation(this.projectionMode === 'plane');
|
||||
|
||||
const material = this.getMaterial();
|
||||
const activeContentMesh = this.getActiveContentMesh();
|
||||
if (material && activeContentMesh) {
|
||||
material.map = mediaTexture;
|
||||
material.needsUpdate = true;
|
||||
this.callbacks.showActiveContentMesh();
|
||||
}
|
||||
|
||||
this.callbacks.togglePlayPause();
|
||||
this.addEventListeners(canvas);
|
||||
this.controls.show();
|
||||
this.positionControls();
|
||||
this.render();
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.active = false;
|
||||
|
||||
const renderer = this.getRenderer();
|
||||
if (renderer?.domElement) {
|
||||
this.removeEventListeners(renderer.domElement);
|
||||
hideRendererCanvas(renderer);
|
||||
} else {
|
||||
this.removeFullscreenEventListeners();
|
||||
}
|
||||
|
||||
this.controls.hide();
|
||||
this.getCameraControls()?.reset();
|
||||
this.callbacks.positionPlaneForPresentation(false);
|
||||
|
||||
const video = this.getVideo();
|
||||
if (video) {
|
||||
video.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
resize(): boolean {
|
||||
if (!this.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const renderer = this.getRenderer();
|
||||
const camera = this.getCamera();
|
||||
if (renderer && camera) {
|
||||
this.resizeCanvasFor2D(renderer, camera);
|
||||
this.positionControls();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
showControls(): void {
|
||||
this.controls.show();
|
||||
}
|
||||
|
||||
hideControls(): void {
|
||||
this.controls.hide();
|
||||
}
|
||||
|
||||
updateTimeline(): void {
|
||||
if (!this.active) return;
|
||||
|
||||
const video = this.getVideo();
|
||||
if (video) {
|
||||
this.controls.updateTime(video.currentTime, video.duration);
|
||||
}
|
||||
}
|
||||
|
||||
updatePlaybackButton(): void {
|
||||
if (!this.active) return;
|
||||
|
||||
const video = this.getVideo();
|
||||
if (video) {
|
||||
this.controls.updatePlaybackButton(video.paused || video.ended);
|
||||
}
|
||||
}
|
||||
|
||||
updateMuteButton(): void {
|
||||
if (!this.active) return;
|
||||
|
||||
const video = this.getVideo();
|
||||
if (video) {
|
||||
this.controls.updateMuteButton(video.muted);
|
||||
}
|
||||
}
|
||||
|
||||
handleVideoEnd(): void {
|
||||
if (!this.active) return;
|
||||
|
||||
this.controls.showPersistent();
|
||||
this.updatePlaybackButton();
|
||||
}
|
||||
|
||||
private addEventListeners(canvas: HTMLElement): void {
|
||||
this.getCameraControls()?.addEventListeners(canvas, this.projectionMode);
|
||||
document.addEventListener('fullscreenchange', this.onFullscreenChange);
|
||||
document.addEventListener('webkitfullscreenchange', this.onFullscreenChange);
|
||||
document.addEventListener('mozfullscreenchange', this.onFullscreenChange);
|
||||
document.addEventListener('MSFullscreenChange', this.onFullscreenChange);
|
||||
}
|
||||
|
||||
private removeEventListeners(canvas: HTMLElement): void {
|
||||
this.getCameraControls()?.removeEventListeners(canvas);
|
||||
this.removeFullscreenEventListeners();
|
||||
}
|
||||
|
||||
private removeFullscreenEventListeners(): void {
|
||||
document.removeEventListener('fullscreenchange', this.onFullscreenChange);
|
||||
document.removeEventListener('webkitfullscreenchange', this.onFullscreenChange);
|
||||
document.removeEventListener('mozfullscreenchange', this.onFullscreenChange);
|
||||
document.removeEventListener('MSFullscreenChange', this.onFullscreenChange);
|
||||
}
|
||||
|
||||
private readonly onFullscreenChange = (): void => {
|
||||
if (!this.active) return;
|
||||
|
||||
window.setTimeout(() => {
|
||||
this.resize();
|
||||
}, FULLSCREEN_RESIZE_DELAY);
|
||||
};
|
||||
|
||||
positionControls(): void {
|
||||
const renderer = this.getRenderer();
|
||||
if (renderer?.domElement) {
|
||||
this.controls.position(renderer.domElement);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly render = (): void => {
|
||||
if (!this.active) return;
|
||||
|
||||
const camera = this.getCamera();
|
||||
if (this.projectionMode === 'vr180') {
|
||||
this.getCameraControls()?.updateCameraRotation();
|
||||
} else if (camera) {
|
||||
camera.rotation.set(0, 0, 0);
|
||||
}
|
||||
|
||||
const renderer = this.getRenderer();
|
||||
const scene = this.getScene();
|
||||
if (renderer && camera && scene) {
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
requestAnimationFrame(this.render);
|
||||
};
|
||||
|
||||
private resizeCanvasFor2D(renderer: any, camera: any): void {
|
||||
resizeFallbackRenderer({
|
||||
camera2D: camera,
|
||||
playerContainer: this.playerContainer,
|
||||
renderer
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user