Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions manimlib/camera/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
from typing import Optional
from manimlib.typing import ManimColor, Vect3
from manimlib.window import Window
from manimlib.scene.scene import Scene


class Camera(object):
def __init__(
self,
window: Optional[Window] = None,
scene: Optional[Scene] = None,
background_image: Optional[str] = None,
frame_config: dict = dict(),
# Note: frame height and width will be resized to match this resolution aspect ratio
Expand All @@ -44,8 +46,10 @@ def __init__(
# without multisampling, for 3d scenes one might want
# to set samples to be greater than 0.
samples: int = 0,
imgui: bool = True,
):
self.window = window
self.scene = scene
self.background_image = background_image
self.default_pixel_shape = resolution # Rename?
self.fps = fps
Expand All @@ -55,6 +59,7 @@ def __init__(
self.pixel_array_dtype = pixel_array_dtype
self.light_source_position = light_source_position
self.samples = samples
self.imgui = imgui

self.rgb_max_val: float = np.iinfo(self.pixel_array_dtype).max
self.background_rgba: list[float] = list(color_to_rgba(
Expand Down Expand Up @@ -230,6 +235,9 @@ def capture(self, *mobjects: Mobject) -> None:
mobject.render(self.ctx, self.uniforms)

if self.window:
if self.imgui and self.scene is not None:
self.scene.construct_imgui_window()
self.scene.render_imgui()
self.window.swap_buffers()
if self.fbo is not self.window_fbo:
self.blit(self.fbo, self.window_fbo)
Expand Down
25 changes: 20 additions & 5 deletions manimlib/scene/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from contextlib import contextmanager
from contextlib import ExitStack

import imgui

import numpy as np
from tqdm.auto import tqdm as ProgressDisplay
from pyglet.window import key as PygletWindowKeys
Expand Down Expand Up @@ -60,6 +62,7 @@ class Scene(object):
samples = 0
# Euler angles, in degrees
default_frame_orientation = (0, 0)
imgui: bool = False

def __init__(
self,
Expand Down Expand Up @@ -102,10 +105,12 @@ def __init__(
self.window.init_for_scene(self)
# Make sure camera and Pyglet window sync
self.camera_config["fps"] = 30
self.camera_config["imgui"] = self.imgui

# Core state of the scene
self.camera: Camera = Camera(
window=self.window,
scene=self,
samples=self.samples,
**self.camera_config
)
Expand Down Expand Up @@ -154,6 +159,7 @@ def run(self) -> None:
self.setup()
try:
self.construct()
self.construct_imgui_window()
self.interact()
except EndScene:
pass
Expand All @@ -176,6 +182,9 @@ def construct(self) -> None:
# To be implemented in subclasses
pass

def construct_imgui_window(self):
pass

def tear_down(self) -> None:
self.stop_skipping()
self.file_writer.finish()
Expand Down Expand Up @@ -220,6 +229,10 @@ def embed(

# Only these methods should touch the camera

def render_imgui(self):
imgui.render()
self.window.impl.render(imgui.get_draw_data())

def get_image(self) -> Image:
if self.window is not None:
self.camera.use_window_fbo(False)
Expand Down Expand Up @@ -766,7 +779,8 @@ def on_mouse_drag(
) -> None:
self.mouse_drag_point.move_to(point)
if self.drag_to_pan:
self.frame.shift(-d_point)
if not self.window.io.want_capture_mouse:
self.frame.shift(-d_point)

event_data = {"point": point, "d_point": d_point, "buttons": buttons, "modifiers": modifiers}
propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseDragEvent, **event_data)
Expand Down Expand Up @@ -809,10 +823,11 @@ def on_mouse_scroll(
return

rel_offset = y_pixel_offset / self.camera.get_pixel_height()
self.frame.scale(
1 - self.scroll_sensitivity * rel_offset,
about_point=point
)
if not self.window.io.want_capture_mouse:
self.frame.scale(
1 - self.scroll_sensitivity * rel_offset,
about_point=point
)

def on_key_release(
self,
Expand Down
20 changes: 20 additions & 0 deletions manimlib/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import numpy as np

import imgui
from moderngl_window.integrations.imgui import ModernglWindowRenderer
from moderngl_window.context.pyglet.keys import Keys as PygletKeys

import moderngl_window as mglw
from moderngl_window.context.pyglet.window import Window as PygletWindow
from moderngl_window.timers.clock import Timer
Expand Down Expand Up @@ -48,6 +52,10 @@ def __init__(

if self.scene:
self.init_for_scene(scene)

imgui.create_context()
self.impl = ModernglWindowRenderer(self)
self.io = imgui.get_io()

def init_for_scene(self, scene: Scene):
"""
Expand Down Expand Up @@ -150,6 +158,9 @@ def wrapper(self, *args, **kwargs):
func(self, *args, **kwargs)
self._has_undrawn_event = True
return wrapper

def imgui_y(self, y):
return self.height - y

@note_undrawn_event
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:
Expand All @@ -159,6 +170,7 @@ def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:
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)
self.impl.mouse_position_event(x, self.imgui_y(y), dx, dy)

@note_undrawn_event
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int) -> None:
Expand All @@ -168,6 +180,7 @@ def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifier
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)
self.impl.mouse_drag_event(x, self.imgui_y(y), dx, dy)

@note_undrawn_event
def on_mouse_press(self, x: int, y: int, button: int, mods: int) -> None:
Expand All @@ -176,6 +189,7 @@ def on_mouse_press(self, x: int, y: int, button: int, mods: int) -> None:
return
point = self.pixel_coords_to_space_coords(x, y)
self.scene.on_mouse_press(point, button, mods)
self.impl.mouse_press_event(x, self.imgui_y(y), button)

@note_undrawn_event
def on_mouse_release(self, x: int, y: int, button: int, mods: int) -> None:
Expand All @@ -184,6 +198,7 @@ def on_mouse_release(self, x: int, y: int, button: int, mods: int) -> None:
return
point = self.pixel_coords_to_space_coords(x, y)
self.scene.on_mouse_release(point, button, mods)
self.impl.mouse_release_event(x, self.imgui_y(y), button)

@note_undrawn_event
def on_mouse_scroll(self, x: int, y: int, x_offset: float, y_offset: float) -> None:
Expand All @@ -193,6 +208,7 @@ def on_mouse_scroll(self, x: int, y: int, x_offset: float, y_offset: float) -> N
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, x_offset, y_offset)
self.impl.mouse_scroll_event(x_offset, y_offset)

@note_undrawn_event
def on_key_press(self, symbol: int, modifiers: int) -> None:
Expand All @@ -201,6 +217,8 @@ def on_key_press(self, symbol: int, modifiers: int) -> None:
if not self.scene:
return
self.scene.on_key_press(symbol, modifiers)
self.impl.key_event(symbol, PygletKeys.ACTION_PRESS, modifiers)
self.io.add_input_character(symbol)

@note_undrawn_event
def on_key_release(self, symbol: int, modifiers: int) -> None:
Expand All @@ -209,13 +227,15 @@ def on_key_release(self, symbol: int, modifiers: int) -> None:
if not self.scene:
return
self.scene.on_key_release(symbol, modifiers)
self.impl.key_event(symbol, PygletKeys.ACTION_RELEASE, modifiers)

@note_undrawn_event
def on_resize(self, width: int, height: int) -> None:
super().on_resize(width, height)
if not self.scene:
return
self.scene.on_resize(width, height)
self.impl.resize(width, height)

@note_undrawn_event
def on_show(self) -> None:
Expand Down