File size: 4,454 Bytes
e6b949c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
104
105
106
107
108
109
110
111
112
import * as SPLAT from "gsplat";
import { InputMode } from "./InputMode";
import { Engine } from "./Engine";
import { ModeManager } from "./ModeManager";
import { SelectionManager } from "./SelectionManager";
import { UndoManager } from "./UndoManager";
import { ScaleAction } from "./ScaleAction";

class ScaleMode implements InputMode {
    exit: () => void;

    constructor(engine: Engine) {
        const splat = SelectionManager.selectedSplat as SPLAT.Splat;
        const initialMousePosition = engine.mouseManager.currentMousePosition.clone();
        const initialScale = splat.scale.clone();

        let axis: "x" | "y" | "z" | null = null;

        const handleClick = () => {
            const action = new ScaleAction(splat, initialScale, splat.scale);
            UndoManager.do(action);
            ModeManager.enterMode("default");
        };

        const handleCancel = () => {
            splat.scale = initialScale;
            ModeManager.enterMode("default");
        };

        const handleMouseMove = () => {
            const plane = new SPLAT.Plane(engine.camera.forward, splat.position);
            const initialDirection = engine.camera.screenPointToRay(initialMousePosition.x, initialMousePosition.y);
            const newDirection = engine.camera.screenPointToRay(
                engine.mouseManager.currentMousePosition.x,
                engine.mouseManager.currentMousePosition.y,
            );
            const initialIntersection = plane.intersect(engine.camera.position, initialDirection);
            const newIntersection = plane.intersect(engine.camera.position, newDirection);
            if (initialIntersection && newIntersection) {
                const initialDistance = initialIntersection.subtract(splat.position).magnitude();
                const distance = newIntersection.subtract(splat.position).magnitude();
                const scaleRatio = distance / initialDistance;
                let scaleAxis = SPLAT.Vector3.One();
                switch (axis) {
                    case "x":
                        scaleAxis = new SPLAT.Vector3(1, 0, 0);
                        break;
                    case "y":
                        scaleAxis = new SPLAT.Vector3(0, 1, 0);
                        break;
                    case "z":
                        scaleAxis = new SPLAT.Vector3(0, 0, 1);
                        break;
                }
                scaleAxis = splat.rotation.apply(scaleAxis);
                scaleAxis = new SPLAT.Vector3(Math.abs(scaleAxis.x), Math.abs(scaleAxis.y), Math.abs(scaleAxis.z));
                const scaling = scaleAxis.multiply(scaleRatio).add(SPLAT.Vector3.One().subtract(scaleAxis));
                splat.scale = initialScale.multiply(scaling);
            }
        };

        const handleAxisX = () => {
            if (axis === "x") {
                axis = null;
            } else {
                axis = "x";
            }
            handleMouseMove();
        };

        const handleAxisY = () => {
            if (axis === "y") {
                axis = null;
            } else {
                axis = "y";
            }
            handleMouseMove();
        };

        const handleAxisZ = () => {
            if (axis === "z") {
                axis = null;
            } else {
                axis = "z";
            }
            handleMouseMove();
        };

        engine.mouseManager.registerMouse("click", handleClick);
        engine.mouseManager.registerMouse("contextmenu", handleCancel);
        engine.mouseManager.registerMouse("mousemove", handleMouseMove);
        engine.keyboardManager.registerKey("Escape", handleCancel);
        engine.keyboardManager.registerKey("s", handleCancel);
        engine.keyboardManager.registerKey("x", handleAxisX);
        engine.keyboardManager.registerKey("y", handleAxisY);
        engine.keyboardManager.registerKey("z", handleAxisZ);

        this.exit = () => {
            engine.mouseManager.unregisterMouse("click");
            engine.mouseManager.unregisterMouse("contextmenu");
            engine.mouseManager.unregisterMouse("mousemove");
            engine.keyboardManager.unregisterKey("Escape");
            engine.keyboardManager.unregisterKey("s");
            engine.keyboardManager.unregisterKey("x");
            engine.keyboardManager.unregisterKey("y");
            engine.keyboardManager.unregisterKey("z");
        };
    }
}

export { ScaleMode };