File size: 3,902 Bytes
d49f7bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
113
114
115
116
117
118
# Copyright (c) Meta Platforms, Inc. and affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

""" Interactive Controller Class Module """

import time
from typing import Optional
import glfw

from animated_drawings.controller.controller import Controller
from animated_drawings.model.scene import Scene
from animated_drawings.view.window_view import WindowView
from animated_drawings.config import ControllerConfig


class InteractiveController(Controller):
    """ Interactive Controller Class """

    def __init__(self, cfg: ControllerConfig, scene: Scene, view: WindowView) -> None:
        super().__init__(cfg, scene)

        self.view: WindowView = view
        self.prev_time: float = 0.0  # tracks real-world time passing between run loops
        self.pause: bool = False     # tracks whether time progresses in the scene

        glfw.init()
        glfw.set_key_callback(self.view.win, self._on_key)

    def _on_key(self, _win, key: int, _scancode, action, _mods) -> None:  # noqa: C901

        if action not in (glfw.PRESS, glfw.REPEAT):
            return

        # close window
        if key in (glfw.KEY_ESCAPE, glfw.KEY_Q):
            glfw.set_window_should_close(self.view.win, True)

        # move camera forward
        elif key == glfw.KEY_W:
            _, _, fwd = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(-0.1 * fwd)

        # move camera back
        elif key == glfw.KEY_S:
            _, _, fwd = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(0.1 * fwd)

        # move camera right
        elif key == glfw.KEY_A:
            right, _, _ = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(-0.1 * right)

        # move camera left
        elif key == glfw.KEY_D:
            right, _, _ = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(0.1 * right)

        # move camera up
        elif key == glfw.KEY_E:
            _, up, _ = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(0.1 * up)

        # move camera down
        elif key == glfw.KEY_R:
            _, up, _ = self.view.camera.get_right_up_fwd_vectors()
            self.view.camera.offset(-0.1 * up)

        # toggle start/stop time
        elif key == glfw.KEY_SPACE:
            self.pause = not self.pause
            self.prev_time = time.time()

        # step forward in time
        elif key == glfw.KEY_RIGHT:
            self._tick(self.cfg.keyboard_timestep)

        # step backward in time
        elif key == glfw.KEY_LEFT:
            self._tick(-self.cfg.keyboard_timestep)

    def _is_run_over(self) -> None:
        return glfw.window_should_close(self.view.win)

    def _prep_for_run_loop(self) -> None:
        self.prev_time = time.time()

    def _start_run_loop_iteration(self) -> None:
        self.view.clear_window()

    def _tick(self, delta_t: Optional[float] = None) -> None:
        # if passed a specific value to progress time by, do so
        if delta_t:
            self.scene.progress_time(delta_t)
        # otherwise, if scene is paused, do nothing
        elif self.pause:
            pass
        # otherwise, calculate real time passed since last call and progress scene by that amount
        else:
            cur_time = time.time()
            self.scene.progress_time(cur_time - self.prev_time)
            self.prev_time = cur_time

    def _update(self) -> None:
        self.scene.update_transforms()

    def _handle_user_input(self) -> None:
        glfw.poll_events()

    def _render(self) -> None:
        self.view.render(self.scene)

    def _finish_run_loop_iteration(self) -> None:
        self.view.swap_buffers()

    def _cleanup_after_run_loop(self) -> None:
        self.view.cleanup()