1 module sbylib.graphics.util.cameracontrol;
2 
3 import sbylib.graphics.camera : Camera;
4 import sbylib.event;
5 import sbylib.math;
6 import sbylib.wrapper.glfw;
7 
8 class CameraControl {
9 
10     EventContext context;
11     alias context this;
12 
13     private Window window;
14     private Camera camera;
15     private vec3 arrivalPos;
16     private quat arrivalRot;
17 
18     float speed;
19 
20     this(Window window, Camera camera) {
21         this.window = window;
22         this.camera = camera;
23         this.context = new EventContext;
24         this.arrivalPos = camera.pos;
25         this.arrivalRot = quat(0,0,0,1);
26         this.speed = 0.03;
27 
28         with (context()) {
29             vec2 basePoint;
30             when(MouseButton.Button1.pressed.on(window)).then({basePoint = window.mousePos;});
31             when(MouseButton.Button1.pressed.on(window)).then({
32                 if (window.cursorMode == CursorMode.Normal) {
33                     window.cursorMode = CursorMode.Disabled;
34                 } else {
35                     window.cursorMode = CursorMode.Normal;
36                 }
37             });
38 
39             alias accel = (vec3 v) { 
40                 if (KeyButton.LeftShift.isPressed.on(window)) {
41                     this.arrivalPos += v * speed * 2;  
42                 } else {
43                     this.arrivalPos += v * speed; 
44                 }
45             };
46             when(KeyButton.KeyA.pressing.on(window)).then({ accel(-camera.rot.column[0]); });
47             when(KeyButton.KeyD.pressing.on(window)).then({ accel(+camera.rot.column[0]); });
48             when(KeyButton.KeyQ.pressing.on(window)).then({ accel(-camera.rot.column[1]); });
49             when(KeyButton.KeyE.pressing.on(window)).then({ accel(+camera.rot.column[1]); });
50             when(KeyButton.KeyW.pressing.on(window)).then({ accel(-camera.rot.column[2]); });
51             when(KeyButton.KeyS.pressing.on(window)).then({ accel(+camera.rot.column[2]); });
52             when((Ctrl + KeyButton.KeyD).pressed.on(window)).then({ window.shouldClose = true; });
53 
54             when(mouse.moved.on(window)).then({
55                 if (window.cursorMode == CursorMode.Normal) return;
56                 auto dif = -(vec2(window.mousePos) - basePoint) * 0.003;
57                 auto angle = dif.length.rad;
58                 auto axis = safeNormalize(arrivalRot.toMatrix3 * vec3(dif.y, dif.x, 0));
59                 arrivalRot = quat.axisAngle(axis, angle) * arrivalRot;
60                 auto forward = arrivalRot.baseZ;
61                 auto side = normalize(cross(vec3(0,1,0), forward));
62                 auto up = normalize(cross(forward, side));
63                 arrivalRot = mat3(side, up, forward).toQuaternion;
64                 basePoint = window.mousePos;
65             });
66 
67             when(Frame).then({
68                 camera.pos = mix(camera.pos, arrivalPos, 0.1);
69                 camera.rot = slerp(camera.rot.toQuaternion, arrivalRot, 0.1).normalize.toMatrix3;
70             });
71 
72             when(context.unbound).then({
73                 window.cursorMode = CursorMode.Normal;
74             });
75         }
76     }
77 
78     ~this() {
79         context.destroy();
80         window.cursorMode = CursorMode.Normal;
81     }
82 }