コード例 #1
0
def run_window_config(config_cls: WindowConfig, timer=None, args=None) -> None:
    """
    Run an WindowConfig entering a blocking main loop

    Args:
        config_cls: The WindowConfig class to render
        args: Override sys.args
    """
    setup_basic_logging(config_cls.log_level)
    parser = create_parser()
    config_cls.add_arguments(parser)
    values = parse_args(args=args, parser=parser)
    config_cls.argv = values
    window_cls = get_local_window_cls(values.window)

    # Calculate window size
    size = values.size or config_cls.window_size
    size = int(size[0] * values.size_mult), int(size[1] * values.size_mult)

    # Resolve cursor
    show_cursor = values.cursor
    if show_cursor is None:
        show_cursor = config_cls.cursor

    window = window_cls(
        title=config_cls.title,
        size=size,
        fullscreen=config_cls.fullscreen or values.fullscreen,
        resizable=values.resizable
        if values.resizable is not None else config_cls.resizable,
        gl_version=config_cls.gl_version,
        aspect_ratio=config_cls.aspect_ratio,
        vsync=values.vsync if values.vsync is not None else config_cls.vsync,
        samples=values.samples
        if values.samples is not None else config_cls.samples,
        cursor=show_cursor if show_cursor is not None else True,
    )
    window.print_context_info()
    activate_context(window=window)
    timer = Timer()
    window.config = config_cls(ctx=window.ctx, wnd=window, timer=timer)

    timer.start()

    while not window.is_closing:
        current_time, delta = timer.next_frame()

        if window.config.clear_color is not None:
            window.clear(*window.config.clear_color)
        else:
            window.use()
        window.render(current_time, delta)
        window.swap_buffers()

    _, duration = timer.stop()
    window.destroy()
    if duration > 0:
        logger.info("Duration: {0:.2f}s @ {1:.2f} FPS".format(
            duration, window.frames / duration))
コード例 #2
0
    def __init__(
        self,
        source: Union[moderngl.Texture, moderngl.Framebuffer] = None,
        framerate: Union[int, float] = 60,
    ):

        self._source = source
        self._framerate = framerate

        self._recording = False

        self._last_time: float = None
        self._filename: str = None
        self._width: int = None
        self._height: int = None

        self._timer = Timer()

        self._components: int = None  # for textures

        if isinstance(self._source, moderngl.Texture):
            self._components = self._source.components
コード例 #3
0
ファイル: window.py プロジェクト: acm-clan/manim
    def __init__(self, scene, size=(1280, 720), **kwargs):
        super().__init__(size=size)
        digest_config(self, kwargs)

        self.scene = scene
        self.pressed_keys = set()
        self.title = str(scene)
        self.size = size
        print("window pixel ratio:", self.pixel_ratio)

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)
        self.timer.start()

        # No idea why, but when self.position is set once
        # it sometimes doesn't actually change the position
        # to the specified tuple on the rhs, but doing it
        # twice seems to make it work.  ¯\_(ツ)_/¯
        initial_position = self.find_initial_position(size)
        self.position = initial_position
        self.position = initial_position
コード例 #4
0
    def __init__(self, renderer, size=config.window_size, **kwargs):
        monitors = get_monitors()
        mon_index = config.window_monitor
        monitor = monitors[min(mon_index, len(monitors) - 1)]

        if size == "default":
            # make window_width half the width of the monitor
            # but make it full screen if --fullscreen

            window_width = monitor.width
            if not config.fullscreen:
                window_width //= 2

            #  by default window_height = 9/16 * window_width
            window_height = int(
                window_width * config.frame_height // config.frame_width, )
            size = (window_width, window_height)
        else:
            size = tuple(size)

        super().__init__(size=size)

        self.title = f"Manim Community {__version__}"
        self.size = size
        self.renderer = renderer

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx,
                                        wnd=self,
                                        timer=self.timer)
        self.timer.start()

        self.swap_buffers()

        initial_position = self.find_initial_position(size, monitor)
        self.position = initial_position
コード例 #5
0
    def test_clock_timer(self):
        """Quick and dirty scheduling test"""
        timer = Timer()
        timer.start()

        scheduler = Scheduler(timer)
        self.test_value = False
        scheduler.run_once(self.set_value, 0.1, arguments=(True, ))
        time.sleep(0.11)
        scheduler.execute()
        self.assertTrue(self.test_value)

        self.test_value = 0
        event = scheduler.run_every(self.increase_value, 0.1)
        for _ in range(30):
            # simulate a render loop
            scheduler.execute()
            time.sleep(0.01)
        self.assertEqual(self.test_value, 3)

        scheduler.cancel(event)
        time.sleep(0.2)
        scheduler.execute()
        self.assertEqual(self.test_value, 3)
コード例 #6
0
def run_window_config(config_cls: WindowConfig, timer=None, args=None) -> None:
    """
    Run an WindowConfig entering a blocking main loop

    Args:
        config_cls: The WindowConfig class to render
        args: Override sys.args
    """
    values = parse_args(args)
    window_cls = get_local_window_cls(values.window)

    window = window_cls(
        title=config_cls.title,
        size=config_cls.window_size,
        fullscreen=values.fullscreen,
        resizable=config_cls.resizable,
        gl_version=config_cls.gl_version,
        aspect_ratio=config_cls.aspect_ratio,
        vsync=values.vsync,
        samples=values.samples,
        cursor=values.cursor,
    )
    window.print_context_info()

    window.config = config_cls(ctx=window.ctx, wnd=window)

    timer = Timer()
    timer.start()

    while not window.is_closing:
        current_time, delta = timer.next_frame()

        window.ctx.screen.use()
        window.render(current_time, delta)
        window.swap_buffers()

    _, duration = timer.stop()
    window.destroy()
    print("Duration: {0:.2f}s @ {1:.2f} FPS".format(duration, window.frames / duration))
コード例 #7
0
def run_window_config(config_cls: WindowConfig, timer=None, args=None) -> None:
    """
    Run an WindowConfig entering a blocking main loop

    Args:
        config_cls: The WindowConfig class to render
    Keyword Args:
        timer: A custom timer instance
        args: Override sys.args
    """
    setup_basic_logging(config_cls.log_level)
    parser = create_parser()
    config_cls.add_arguments(parser)
    values = parse_args(args=args, parser=parser)
    config_cls.argv = values
    window_cls = get_local_window_cls(values.window)

    # Calculate window size
    size = values.size or config_cls.window_size
    size = int(size[0] * values.size_mult), int(size[1] * values.size_mult)

    # Resolve cursor
    show_cursor = values.cursor
    if show_cursor is None:
        show_cursor = config_cls.cursor

    window = window_cls(
        title=config_cls.title,
        size=size,
        fullscreen=config_cls.fullscreen or values.fullscreen,
        resizable=values.resizable
        if values.resizable is not None else config_cls.resizable,
        gl_version=config_cls.gl_version,
        aspect_ratio=config_cls.aspect_ratio,
        vsync=values.vsync if values.vsync is not None else config_cls.vsync,
        samples=values.samples
        if values.samples is not None else config_cls.samples,
        cursor=show_cursor if show_cursor is not None else True,
    )
    window.print_context_info()
    activate_context(window=window)
    timer = timer or Timer()
    config = config_cls(ctx=window.ctx, wnd=window, timer=timer)
    # Avoid the event assigning in the property setter for now
    # We want the even assigning to happen in WindowConfig.__init__
    # so users are free to assign them in their own __init__.
    window._config = weakref.ref(config)

    # Swap buffers once before staring the main loop.
    # This can trigged additional resize events reporting
    # a more accurate buffer size
    window.swap_buffers()
    window.set_default_viewport()

    timer.start()

    while not window.is_closing:
        current_time, delta = timer.next_frame()

        if config.clear_color is not None:
            window.clear(*config.clear_color)

        # Always bind the window framebuffer before calling render
        window.use()

        window.render(current_time, delta)
        if not window.is_closing:
            window.swap_buffers()

    _, duration = timer.stop()
    window.destroy()
    if duration > 0:
        logger.info("Duration: {0:.2f}s @ {1:.2f} FPS".format(
            duration, window.frames / duration))
コード例 #8
0
ファイル: window.py プロジェクト: yk616/manim
class Window(PygletWindow):
    fullscreen = False
    resizable = True
    gl_version = (3, 3)
    vsync = True
    cursor = True

    def __init__(self,
                 scene: Scene,
                 size: tuple[int, int] = (1280, 720),
                 **kwargs):
        super().__init__(size=size)
        digest_config(self, kwargs)

        self.scene = scene
        self.pressed_keys = set()
        self.title = str(scene)
        self.size = size

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx,
                                        wnd=self,
                                        timer=self.timer)
        self.timer.start()

        # No idea why, but when self.position is set once
        # it sometimes doesn't actually change the position
        # to the specified tuple on the rhs, but doing it
        # twice seems to make it work.  ¯\_(ツ)_/¯
        initial_position = self.find_initial_position(size)
        self.position = initial_position
        self.position = initial_position

    def find_initial_position(self, size: tuple[int, int]) -> tuple[int, int]:
        custom_position = get_customization()["window_position"]
        monitors = get_monitors()
        mon_index = get_customization()["window_monitor"]
        monitor = monitors[min(mon_index, len(monitors) - 1)]
        window_width, window_height = size
        # Position might be specified with a string of the form
        # x,y for integers x and y
        if "," in custom_position:
            return tuple(map(int, custom_position.split(",")))

        # Alternatively, it might be specified with a string like
        # UR, OO, DL, etc. specifying what corner it should go to
        char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
        width_diff = monitor.width - window_width
        height_diff = monitor.height - window_height
        return (
            monitor.x + char_to_n[custom_position[1]] * width_diff // 2,
            -monitor.y + char_to_n[custom_position[0]] * height_diff // 2,
        )

    # Delegate event handling to scene
    def pixel_coords_to_space_coords(self,
                                     px: int,
                                     py: int,
                                     relative: bool = False) -> np.ndarray:
        pw, ph = self.size
        fw, fh = self.scene.camera.get_frame_shape()
        fc = self.scene.camera.get_frame_center()
        if relative:
            return np.array([px / pw, py / ph, 0])
        else:
            return np.array([
                fc[0] + px * fw / pw - fw / 2, fc[1] + py * fh / ph - fh / 2, 0
            ])

    def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:
        super().on_mouse_motion(x, y, dx, dy)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_motion(point, d_point)

    def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int,
                      modifiers: int) -> None:
        super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_drag(point, d_point, buttons, modifiers)

    def on_mouse_press(self, x: int, y: int, button: int, mods: int) -> None:
        super().on_mouse_press(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_press(point, button, mods)

    def on_mouse_release(self, x: int, y: int, button: int, mods: int) -> None:
        super().on_mouse_release(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_release(point, button, mods)

    def on_mouse_scroll(self, x: int, y: int, x_offset: float,
                        y_offset: float) -> None:
        super().on_mouse_scroll(x, y, x_offset, y_offset)
        point = self.pixel_coords_to_space_coords(x, y)
        offset = self.pixel_coords_to_space_coords(x_offset,
                                                   y_offset,
                                                   relative=True)
        self.scene.on_mouse_scroll(point, offset)

    def on_key_press(self, symbol: int, modifiers: int) -> None:
        self.pressed_keys.add(symbol)  # Modifiers?
        super().on_key_press(symbol, modifiers)
        self.scene.on_key_press(symbol, modifiers)

    def on_key_release(self, symbol: int, modifiers: int) -> None:
        self.pressed_keys.difference_update({symbol})  # Modifiers?
        super().on_key_release(symbol, modifiers)
        self.scene.on_key_release(symbol, modifiers)

    def on_resize(self, width: int, height: int) -> None:
        super().on_resize(width, height)
        self.scene.on_resize(width, height)

    def on_show(self) -> None:
        super().on_show()
        self.scene.on_show()

    def on_hide(self) -> None:
        super().on_hide()
        self.scene.on_hide()

    def on_close(self) -> None:
        super().on_close()
        self.scene.on_close()

    def is_key_pressed(self, symbol: int) -> bool:
        return (symbol in self.pressed_keys)
コード例 #9
0
ファイル: video_rec.py プロジェクト: sthagen/moderngl-window
class VideoCapture:
    """
        ``VideoCapture`` it's an utility class to capture runtime render
        and save it as video. 
        
        Example:

        .. code:: python

            import moderngl_window
            from moderngl_window.capture import VideoCapture

            class CaptureTest(modenrgl_window.WindowConfig):
                
                def __init__(self, **kwargs):
                    super().__init__(**kwargs)
                    # do other initialization 

                    # define VideoCapture class
                    self.cap = VideoCapture()

                    # start recording
                    self.cap.start_capture(
                        filename="video.mp4",
                        target_fb = self.wnd.fbo
                    )
                
                def render(self, time, frametime):
                    # do other render stuff

                    # call record function after
                    self.cap.dump()
                
                def close(self):
                    # if realease func is not called during 
                    # runtime. make sure to do it on the closing event
                    self.cap.release()


    """
    def __init__(self):

        self._ffmpeg = None
        self._video_timer = Timer()

        self._filename: str = None
        self._target_fb: moderngl.Framebuffer = None
        self._framerate: int = None

        self._last_frame = None
        self._recording = False
    
    @property
    def framerate(self) -> int:
        return self._framerate
    
    @framerate.setter
    def framerate(self, value: int):
        self._framerate = value
    
    @property
    def target_fb(self) -> moderngl.Framebuffer:
        return self._target_fb
    
    @target_fb.setter
    def target_fb(self, value: moderngl.Framebuffer):
        self._target_fb = value
    
    @property
    def filename(self) -> str:
        return self._filename
    
    @filename.setter
    def filename(self, value: str):
        self._filename = value
    

    def dump(self):
        """ Read data from the target framebuffer and dump the raw data 
            into ffmpeg stdin. 
            Call this function at the end of `render` function 
            
            Frame are saved respecting the video framerate.
        """
        if not self._recording:
            return
        
        # in theory to capture a frame at certain speed i'm testing if
        # the time passed after the last frame is at least dt = 1./target_fps .
        # This prevent the higher framerate during runtime to exceed the 
        # target framerate of the video. This doesn't work if runtime framerate 
        # is lower than target framerate.
        if  (self._video_timer.time - self._last_frame) >= 1./self._framerate:
            data = self._target_fb.read(components=3)
            self._ffmpeg.stdin.write(data)
            self._last_frame = self._video_timer.time


    def start(self, filename: str = None, target_fb: moderngl.Framebuffer = None, framerate=60):
        """
            Start ffmpeg pipe subprocess. 
            Call this at the end of __init__ function.

            Args:
                filename (str): name of the output file
                fb (moderngl.Framebuffer): target framebuffer to record
                framerate (int): framerate of the video

        """
        if not target_fb:
            raise Exception("target framebuffer can't be: None")
        else:
            self._target_fb = target_fb

        self._framerate = framerate
            
        if not filename:
            now = datetime.datetmie.now()
            filename = f'video_{now:%Y-%m-%d_%H:%M:%S.%f}.mp4'
        
        self._filename = filename
        
        width = target_fb.width
        height = target_fb.height

        # took from Wasaby2D project
        command = [
            'ffmpeg',
            '-y',  # (optional) overwrite output file if it exists
            '-f', 'rawvideo',
            '-vcodec', 'rawvideo',
            '-s', f'{width}x{height}',  # size of one frame
            '-pix_fmt', 'rgb24',
            '-r', f'{framerate}',  # frames per second
            '-i', '-',  # The imput comes from a pipe
            '-vf', 'vflip',
            '-an',  # Tells FFMPEG not to expect any audio
            filename,
        ]
        
        # ffmpeg binary need to be on the PATH.
        try:
            self._ffmpeg = subprocess.Popen(
                command,
                stdin=subprocess.PIPE,
                bufsize=0
            )
        except FileNotFoundError:
            print("ffmpeg command not found.")
            return

        self._video_timer.start()
        self._last_frame = self._video_timer.time

        self._recording = True
        print("Started video Recording")

    def release(self):
        """
        Stop the recording process
        """
        if self._recording:
            self._ffmpeg.stdin.close()
            ret = self._ffmpeg.wait()
            if ret == 0:
                print("Video saved succesfully")
            else:
                print("Error writing video.")
            self._recording = None
            self._video_timer.stop()
コード例 #10
0
class Window(PygletWindow):
    fullscreen = False
    resizable = True
    gl_version = (3, 3)
    vsync = True
    cursor = True

    def __init__(self, renderer, size=None, **kwargs):
        if size is None:
            # Default to making window half the screen size
            # but make it full screen if --fullscreen is passed in
            monitors = get_monitors()
            mon_index = config.window_monitor
            monitor = monitors[min(mon_index, len(monitors) - 1)]
            window_width = monitor.width

            if not config.fullscreen:
                window_width //= 2

            window_height = int(window_width * config.frame_height //
                                config.frame_width)
            size = (window_width, window_height)

        super().__init__(size=size)

        self.title = f"Manim Community {__version__}"
        self.size = size
        self.renderer = renderer

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx,
                                        wnd=self,
                                        timer=self.timer)
        self.timer.start()

        self.swap_buffers()

        initial_position = self.find_initial_position(size, monitor)
        self.position = initial_position

    # Delegate event handling to scene.
    def on_mouse_motion(self, x, y, dx, dy):
        super().on_mouse_motion(x, y, dx, dy)
        point = self.renderer.pixel_coords_to_space_coords(x, y)
        d_point = self.renderer.pixel_coords_to_space_coords(dx,
                                                             dy,
                                                             relative=True)
        self.renderer.scene.on_mouse_motion(point, d_point)

    def on_mouse_scroll(self, x, y, x_offset: float, y_offset: float):
        super().on_mouse_scroll(x, y, x_offset, y_offset)
        point = self.renderer.pixel_coords_to_space_coords(x, y)
        offset = self.renderer.pixel_coords_to_space_coords(x_offset,
                                                            y_offset,
                                                            relative=True)
        self.renderer.scene.on_mouse_scroll(point, offset)

    def on_key_press(self, symbol, modifiers):
        self.renderer.pressed_keys.add(symbol)
        super().on_key_press(symbol, modifiers)
        self.renderer.scene.on_key_press(symbol, modifiers)

    def on_key_release(self, symbol, modifiers):
        if symbol in self.renderer.pressed_keys:
            self.renderer.pressed_keys.remove(symbol)
        super().on_key_release(symbol, modifiers)
        self.renderer.scene.on_key_release(symbol, modifiers)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
        point = self.renderer.pixel_coords_to_space_coords(x, y)
        d_point = self.renderer.pixel_coords_to_space_coords(dx,
                                                             dy,
                                                             relative=True)
        self.renderer.scene.on_mouse_drag(point, d_point, buttons, modifiers)

    def find_initial_position(self, size, monitor):
        custom_position = config.window_position
        window_width, window_height = size
        # Position might be specified with a string of the form
        # x,y for integers x and y
        if len(custom_position) == 1:
            raise ValueError(
                "window_position must specify both Y and X positions (Y/X -> UR). Also accepts LEFT/RIGHT/ORIGIN/UP/DOWN."
            )
        # in the form Y/X (UR)
        if custom_position == "LEFT" or custom_position == "RIGHT":
            custom_position = "O" + custom_position[0]
        elif custom_position == "UP" or custom_position == "DOWN":
            custom_position = custom_position[0] + "O"
        elif custom_position == "ORIGIN":
            custom_position = "O" * 2
        elif "," in custom_position:
            return tuple(map(int, custom_position.split(",")))

        # Alternatively, it might be specified with a string like
        # UR, OO, DL, etc. specifying what corner it should go to
        char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
        width_diff = monitor.width - window_width
        height_diff = monitor.height - window_height

        return (
            monitor.x + char_to_n[custom_position[1]] * width_diff // 2,
            -monitor.y + char_to_n[custom_position[0]] * height_diff // 2,
        )
コード例 #11
0
class BaseVideoCapture:
    """
        ``BaseVideoCapture`` is a base class to video capture

        Args:
            source (moderngl.Texture, moderngl.Framebuffer): the source of the capture
            framerate (int, float) : the framerate of the video, by thefault is 60 fps

        if the source is texture there are some requirements:
            - dtype = 'f1';
            - components >= 3.
    """
    def __init__(
        self,
        source: Union[moderngl.Texture, moderngl.Framebuffer] = None,
        framerate: Union[int, float] = 60,
    ):

        self._source = source
        self._framerate = framerate

        self._recording = False

        self._last_time: float = None
        self._filename: str = None
        self._width: int = None
        self._height: int = None

        self._timer = Timer()

        self._components: int = None  # for textures

        if isinstance(self._source, moderngl.Texture):
            self._components = self._source.components

    def _dump_frame(self, frame):
        """
            custom function called during self.save()

            Args:
                frame: frame data in bytes
        """
        raise NotImplementedError("override this function")

    def _start_func(self) -> bool:
        """
            custom function called during self.start_capture()

            must return a True if this function complete without errors
        """
        raise NotImplementedError("override this function")

    def _release_func(self):
        """
            custom function called during self.realease()
        """
        raise NotImplementedError("override this function")

    def _get_wh(self):
        """
            Return a tuple of the width and the height of the source
        """
        return self._source.width, self._source.height

    def _remove_file(self):
        """ Remove the filename of the video is it exist """
        if os.path.exists(self._filename):
            os.remove(self._filename)

    def start_capture(self,
                      filename: str = None,
                      framerate: Union[int, float] = 60):
        """
            Start the capturing process

            Args:
                filename (str): name of the output file
                framerate (int, float): framerate of the video

            if filename is not specified it will be generated based
            on the datetime.
        """
        if self._recording:
            print("Capturing is already started")
            return

        # ensure the texture has the correct dtype and components
        if isinstance(self._source, moderngl.Texture):
            if self._source.dtype != 'f1':
                print("source type: moderngl.Texture must be type `f1` ")
                return
            if self._components < 3:
                print(
                    "source type: moderngl.Texture must have at least 3 components"
                )
                return

        if not filename:
            now = datetime.datetime.now()
            filename = f'video_{now:%Y%m%d_%H%M%S}.mp4'

        self._filename = filename

        self._framerate = framerate
        self._width, self._height = self._get_wh()

        # if something goes wrong with the start
        # function, just stop and release the
        # capturing process
        if not self._start_func():
            self.release()
            print("Capturing failed")
            return

        self._timer.start()
        self._last_time = self._timer.time
        self._recording = True

    def save(self):
        """
            Save function to call at the end of render function
        """
        if not self._recording:
            return

        dt = 1. / self._framerate

        if self._timer.time - self._last_time > dt:

            # start counting
            self._last_time = self._timer.time

            if isinstance(self._source, moderngl.Framebuffer):
                # get data from framebuffer
                frame = self._source.read(components=3)
                self._dump_frame(frame)
            else:
                # get data from texture
                frame = self._source.read()
                self._dump_frame(frame)

    def release(self):
        """
        Stop the recording process
        """
        if self._recording:
            self._release_func()

            self._timer.stop()
            print(f"Video file succesfully saved as {self._filename}")
        self._recording = None
コード例 #12
0
ファイル: window.py プロジェクト: techdude/manim
class Window(PygletWindow):
    fullscreen = False
    resizable = True
    gl_version = (3, 3)
    vsync = True
    samples = 1
    cursor = True

    def __init__(self, scene, **kwargs):
        super().__init__(**kwargs)
        digest_config(self, kwargs)
        self.scene = scene
        self.title = str(scene)
        self.pressed_keys = set()
        self.position = self.find_initial_position()

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)
        self.timer.start()

    def find_initial_position(self):
        custom_position = get_customization()["window_position"]
        monitor = get_monitors()[0]
        window_width, window_height = self.size
        # Position might be specified with a string of the form
        # x,y for integers x and y
        if "," in custom_position:
            return tuple(map(int, custom_position.split(",")))

        # Alternatively, it might be specified with a string like
        # UR, OO, DL, etc. specifiying what corner it should go to
        char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
        width_diff = monitor.width - window_width
        height_diff = monitor.height - window_height
        return (
            char_to_n[custom_position[1]] * width_diff // 2,
            char_to_n[custom_position[0]] * height_diff // 2,
        )

    # Delegate event handling to scene
    def pixel_coords_to_space_coords(self, px, py, relative=False):
        return self.scene.camera.pixel_coords_to_space_coords(px, py, relative)

    def on_mouse_motion(self, x, y, dx, dy):
        super().on_mouse_motion(x, y, dx, dy)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_motion(point, d_point)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_drag(point, d_point, buttons, modifiers)

    def on_mouse_press(self, x: int, y: int, button, mods):
        super().on_mouse_press(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_press(point, button, mods)

    def on_mouse_release(self, x: int, y: int, button, mods):
        super().on_mouse_release(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_release(point, button, mods)

    def on_mouse_scroll(self, x, y, x_offset: float, y_offset: float):
        super().on_mouse_scroll(x, y, x_offset, y_offset)
        point = self.pixel_coords_to_space_coords(x, y)
        offset = self.pixel_coords_to_space_coords(x_offset, y_offset, relative=True)
        self.scene.on_mouse_scroll(point, offset)

    def on_key_press(self, symbol, modifiers):
        self.pressed_keys.add(symbol)  # Modifiers?
        super().on_key_press(symbol, modifiers)
        self.scene.on_key_press(symbol, modifiers)

    def on_key_release(self, symbol, modifiers):
        self.pressed_keys.difference_update({symbol})  # Modifiers?
        super().on_key_release(symbol, modifiers)
        self.scene.on_key_release(symbol, modifiers)

    def on_resize(self, width: int, height: int):
        super().on_resize(width, height)
        self.scene.on_resize(width, height)

    def on_show(self):
        super().on_show()
        self.scene.on_show()

    def on_hide(self):
        super().on_hide()
        self.scene.on_hide()

    def on_close(self):
        super().on_close()
        self.scene.on_close()

    def is_key_pressed(self, symbol):
        return (symbol in self.pressed_keys)
コード例 #13
0
class Window(PygletWindow):
    size = (DEFAULT_PIXEL_WIDTH, DEFAULT_PIXEL_HEIGHT)
    fullscreen = False
    resizable = True
    gl_version = (3, 3)
    vsync = True
    samples = 8
    cursor = True

    def __init__(self, scene, **kwargs):
        digest_config(self, kwargs)
        super().__init__(**kwargs)
        self.scene = scene
        self.title = str(scene)
        # Put at the top of the screen
        self.position = (self.position[0], 0)

        mglw.activate_context(window=self)
        self.timer = Timer()
        self.config = mglw.WindowConfig(ctx=self.ctx,
                                        wnd=self,
                                        timer=self.timer)
        self.timer.start()

    # Delegate event handling to scene
    def pixel_coords_to_space_coords(self, px, py, relative=False):
        return self.scene.camera.pixel_coords_to_space_coords(px, py, relative)

    def on_mouse_motion(self, x, y, dx, dy):
        super().on_mouse_motion(x, y, dx, dy)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_motion(point, d_point)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
        point = self.pixel_coords_to_space_coords(x, y)
        d_point = self.pixel_coords_to_space_coords(dx, dy, relative=True)
        self.scene.on_mouse_drag(point, d_point, buttons, modifiers)

    def on_mouse_press(self, x: int, y: int, button, mods):
        super().on_mouse_press(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_press(point, button, mods)

    def on_mouse_release(self, x: int, y: int, button, mods):
        super().on_mouse_release(x, y, button, mods)
        point = self.pixel_coords_to_space_coords(x, y)
        self.scene.on_mouse_release(point, button, mods)

    def on_mouse_scroll(self, x, y, x_offset: float, y_offset: float):
        super().on_mouse_scroll(x, y, x_offset, y_offset)
        point = self.pixel_coords_to_space_coords(x, y)
        offset = self.pixel_coords_to_space_coords(x_offset,
                                                   y_offset,
                                                   relative=True)
        self.scene.on_mouse_scroll(point, offset)

    def on_key_release(self, symbol, modifiers):
        super().on_key_release(symbol, modifiers)
        self.scene.on_key_release(symbol, modifiers)

    def on_key_press(self, symbol, modifiers):
        super().on_key_press(symbol, modifiers)
        self.scene.on_key_press(symbol, modifiers)

    def on_resize(self, width: int, height: int):
        super().on_resize(width, height)
        self.scene.on_resize(width, height)

    def on_show(self):
        super().on_show()
        self.scene.on_show()

    def on_hide(self):
        super().on_hide()
        self.scene.on_hide()

    def on_close(self):
        super().on_close()
        self.scene.on_close()