mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 02:35:22 +08:00
@ -124,6 +124,8 @@ class Camera(object):
|
||||
|
||||
def clear(self) -> None:
|
||||
self.fbo.clear(*self.background_rgba)
|
||||
if self.window:
|
||||
self.window.clear()
|
||||
|
||||
def blit(self, src_fbo, dst_fbo):
|
||||
"""
|
||||
@ -227,8 +229,11 @@ class Camera(object):
|
||||
self.fbo.use()
|
||||
for mobject in mobjects:
|
||||
mobject.render(self.ctx, self.uniforms)
|
||||
if self.window is not None and self.fbo is not self.window_fbo:
|
||||
self.blit(self.fbo, self.window_fbo)
|
||||
|
||||
if self.window:
|
||||
self.window.swap_buffers()
|
||||
if self.fbo is not self.window_fbo:
|
||||
self.blit(self.fbo, self.window_fbo)
|
||||
|
||||
def refresh_uniforms(self) -> None:
|
||||
frame = self.frame
|
||||
|
@ -214,7 +214,7 @@ class Scene(object):
|
||||
) -> None:
|
||||
if not self.preview:
|
||||
# Embed is only relevant with a preview
|
||||
return
|
||||
return
|
||||
self.stop_skipping()
|
||||
self.update_frame()
|
||||
self.save_state()
|
||||
@ -269,7 +269,7 @@ class Scene(object):
|
||||
# Operation to run after each ipython command
|
||||
def post_cell_func(*args, **kwargs):
|
||||
if not self.is_window_closing():
|
||||
self.update_frame(dt=0, ignore_skipping=True)
|
||||
self.update_frame(dt=0, force_draw=True)
|
||||
|
||||
shell.events.register("post_run_cell", post_cell_func)
|
||||
|
||||
@ -313,28 +313,30 @@ class Scene(object):
|
||||
return image
|
||||
|
||||
def show(self) -> None:
|
||||
self.update_frame(ignore_skipping=True)
|
||||
self.update_frame(force_draw=True)
|
||||
self.get_image().show()
|
||||
|
||||
def update_frame(self, dt: float = 0, ignore_skipping: bool = False) -> None:
|
||||
def update_frame(self, dt: float = 0, force_draw: bool = False) -> None:
|
||||
self.increment_time(dt)
|
||||
self.update_mobjects(dt)
|
||||
if self.skip_animations and not ignore_skipping:
|
||||
if self.skip_animations and not force_draw:
|
||||
return
|
||||
|
||||
if self.is_window_closing():
|
||||
raise EndScene()
|
||||
|
||||
if self.window:
|
||||
self.window.clear()
|
||||
if self.window and dt == 0 and not self.window.has_undrawn_event() and not force_draw:
|
||||
# In this case, there's no need for new rendering, but we
|
||||
# shoudl still listen for new events
|
||||
self.window._window.dispatch_events()
|
||||
return
|
||||
|
||||
self.camera.capture(*self.render_groups)
|
||||
|
||||
if self.window:
|
||||
self.window.swap_buffers()
|
||||
vt = self.time - self.virtual_animation_start_time
|
||||
rt = time.time() - self.real_animation_start_time
|
||||
if rt < vt:
|
||||
self.update_frame(0)
|
||||
time.sleep(max(vt - rt, 0))
|
||||
|
||||
def emit_frame(self) -> None:
|
||||
if not self.skip_animations:
|
||||
@ -530,6 +532,7 @@ class Scene(object):
|
||||
|
||||
def stop_skipping(self) -> None:
|
||||
self.virtual_animation_start_time = self.time
|
||||
self.real_animation_start_time = time.time()
|
||||
self.skip_animations = False
|
||||
|
||||
# Methods associated with running animations
|
||||
@ -596,8 +599,8 @@ class Scene(object):
|
||||
self.file_writer.begin_animation()
|
||||
|
||||
if self.window:
|
||||
self.real_animation_start_time = time.time()
|
||||
self.virtual_animation_start_time = self.time
|
||||
self.real_animation_start_time = time.time()
|
||||
|
||||
def post_play(self):
|
||||
if not self.skip_animations:
|
||||
@ -605,7 +608,7 @@ class Scene(object):
|
||||
|
||||
if self.skip_animations and self.window is not None:
|
||||
# Show some quick frames along the way
|
||||
self.update_frame(dt=0, ignore_skipping=True)
|
||||
self.update_frame(dt=0, force_draw=True)
|
||||
|
||||
self.num_plays += 1
|
||||
|
||||
|
@ -182,7 +182,7 @@ def get_fill_canvas(ctx: moderngl.Context) -> Tuple[Framebuffer, VertexArray]:
|
||||
if(color.a == 0) discard;
|
||||
|
||||
// Counteract scaling in fill frag
|
||||
color.a *= 1.06;
|
||||
color *= 1.06;
|
||||
|
||||
gl_FragDepth = texture(DepthTexture, uv)[0];
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import moderngl_window as mglw
|
||||
from moderngl_window.context.pyglet.window import Window as PygletWindow
|
||||
from moderngl_window.timers.clock import Timer
|
||||
from screeninfo import get_monitors
|
||||
from functools import wraps
|
||||
|
||||
from manimlib.constants import FRAME_SHAPE
|
||||
from manimlib.utils.customization import get_customization
|
||||
@ -39,6 +40,8 @@ class Window(PygletWindow):
|
||||
self.title = str(scene)
|
||||
self.size = size
|
||||
|
||||
self._has_undrawn_event = True
|
||||
|
||||
mglw.activate_context(window=self)
|
||||
self.timer = Timer()
|
||||
self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)
|
||||
@ -95,56 +98,82 @@ class Window(PygletWindow):
|
||||
coords[:2] -= 0.5 * fixed_frame_shape
|
||||
return frame.from_fixed_frame_point(coords, relative)
|
||||
|
||||
def has_undrawn_event(self) -> bool:
|
||||
return self._has_undrawn_event
|
||||
|
||||
def swap_buffers(self):
|
||||
super().swap_buffers()
|
||||
self._has_undrawn_event = False
|
||||
|
||||
@staticmethod
|
||||
def note_undrawn_event(func: Callable[..., T]) -> Callable[..., T]:
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
func(self, *args, **kwargs)
|
||||
self._has_undrawn_event = True
|
||||
return wrapper
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
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, x_offset, y_offset)
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
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)
|
||||
|
||||
@note_undrawn_event
|
||||
def on_resize(self, width: int, height: int) -> None:
|
||||
super().on_resize(width, height)
|
||||
self.scene.on_resize(width, height)
|
||||
|
||||
@note_undrawn_event
|
||||
def on_show(self) -> None:
|
||||
super().on_show()
|
||||
self.scene.on_show()
|
||||
|
||||
@note_undrawn_event
|
||||
def on_hide(self) -> None:
|
||||
super().on_hide()
|
||||
self.scene.on_hide()
|
||||
|
||||
@note_undrawn_event
|
||||
def on_close(self) -> None:
|
||||
super().on_close()
|
||||
self.scene.on_close()
|
||||
|
Reference in New Issue
Block a user