aboutsummaryrefslogtreecommitdiffstats
path: root/src/user/ThreeVideo.ts
blob: 92615f1974b05b2d897192882dfe01022cc29a82 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { Video as BaseVideo, type FrameTime, type InitConfig } from '$/lib/Player/Video';
import * as THREE from 'three';
import type { OrbitControls } from 'three/examples/jsm/Addons.js';

export const OnceCell = <T>(create: () => T) => {
  let called = false,
    cached = null as unknown as T
  return () => {
    if (called) return cached
    else { cached = create(); called = true; return cached }
  }
}

export default abstract class ThreeVideo extends BaseVideo {
  protected abstract ctx: CanvasRenderingContext2D
  protected scene!: THREE.Scene;
  protected camera!: THREE.PerspectiveCamera;
  protected renderer!: THREE.WebGLRenderer;
  protected threeCanvas!: HTMLCanvasElement;
  protected orbitControls?: OrbitControls;
  public async init(_config: InitConfig): Promise<void> {
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75, this.w / this.h, 0.1, 1000);

    const canvas = this.threeCanvas = document.createElement('canvas');
    canvas.width = this.canvas.width
    canvas.height = this.canvas.height
    canvas.style.opacity = "0"
    canvas.style.position = "fixed";
    canvas.style.top = "1000vh"
    canvas.style.left = "1000vw"
    document.body.appendChild(canvas)

    this.renderer = new THREE.WebGLRenderer({
      canvas: canvas,
      alpha: true,
      powerPreference: 'high-performance',
    });
    this.renderer.setSize(this.w, this.h);
    this.renderer.setAnimationLoop(() => this.renderScene());
  }
  public renderScene(ctx?: CanvasRenderingContext2D) {
    if (this.orbitControls)
      this.orbitControls.update()
    this.renderer.render(this.scene, this.camera)
    if (ctx)
      ctx.drawImage(this.threeCanvas, 0, 0)
  }
  public cleanup(): void {
    this.renderer.dispose()
    this.threeCanvas.remove()
  }
}