File size: 3,096 Bytes
ebb3bda
537f2af
ebb3bda
 
ec3121c
 
537f2af
95af024
 
 
ec3121c
cc654e9
bdef08e
1b5e137
ec3121c
cc654e9
95af024
 
 
 
31a2d08
70a459f
 
ec3121c
 
95af024
31a2d08
 
 
 
 
 
 
 
 
 
 
ec3121c
95af024
 
 
ec3121c
95af024
 
ec3121c
 
 
95af024
ec3121c
70a459f
 
 
95af024
1b5e137
bdef08e
70a459f
 
 
 
cc654e9
70a459f
 
95af024
 
ec3121c
cc654e9
 
ebb3bda
c9731fb
70a459f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebb3bda
 
3b7903d
ebb3bda
 
3b7903d
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import type { IViewer } from "./IViewer";
import * as SPLAT from "gsplat";

export class SplatViewer implements IViewer {
    canvas: HTMLCanvasElement;

    renderer: SPLAT.WebGLRenderer;
    scene: SPLAT.Scene;
    camera: SPLAT.Camera;
    controls: SPLAT.OrbitControls;

    disposed: boolean = false;

    constructor(canvas: HTMLCanvasElement) {
        this.canvas = canvas;

        this.renderer = new SPLAT.WebGLRenderer(canvas);
        this.scene = new SPLAT.Scene();
        this.camera = new SPLAT.Camera();
        this.controls = new SPLAT.OrbitControls(this.camera, canvas);
        this.controls.orbitSpeed = 3.0;

        this.handleResize = this.handleResize.bind(this);
    }

    async loadScene(url: string, loadingBarCallback?: (progress: number) => void) {
        if (url.endsWith(".splat")) {
            await SPLAT.Loader.LoadAsync(url, this.scene, (progress) => {
                loadingBarCallback?.(progress);
            });
        } else if (url.endsWith(".ply")) {
            await SPLAT.PLYLoader.LoadAsync(url, this.scene, (progress) => {
                loadingBarCallback?.(progress);
            });
        } else {
            throw new Error("Unsupported file format");
        }

        const frame = () => {
            this.controls.update();
            this.renderer.render(this.scene, this.camera);

            if (!this.disposed) {
                requestAnimationFrame(frame);
            }
        };

        this.disposed = false;

        this.handleResize();
        window.addEventListener("resize", this.handleResize);

        requestAnimationFrame(frame);
    }

    handleResize() {
        this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
    }

    dispose() {
        window.removeEventListener("resize", this.handleResize);

        this.controls.dispose();
        this.renderer.dispose();

        this.disposed = true;
    }

    async capture(): Promise<string | null> {
        return new Promise((resolve) => {
            requestAnimationFrame(() => {
                const offscreenCanvas = document.createElement("canvas");
                offscreenCanvas.width = 512;
                offscreenCanvas.height = 512;
                const offscreenContext = offscreenCanvas.getContext("2d") as CanvasRenderingContext2D;

                const x = (this.canvas.width - offscreenCanvas.width) / 2;
                const y = (this.canvas.height - offscreenCanvas.height) / 2;

                offscreenContext.drawImage(
                    this.canvas,
                    x,
                    y,
                    offscreenCanvas.width,
                    offscreenCanvas.height,
                    0,
                    0,
                    offscreenCanvas.width,
                    offscreenCanvas.height
                );
                const dataUrl = offscreenCanvas.toDataURL("image/png");
                offscreenCanvas.remove();

                resolve(dataUrl);
            });
        });
    }

    getStats(): { name: string; value: any }[] {
        return [];
    }
}