Skip to content

Add rendering loop to experimental #3707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f46e116
try adding a render manager
JasonGrace2282 Apr 11, 2024
1d5024a
Add a test scene
JasonGrace2282 Apr 16, 2024
c942de0
Got keys working
JasonGrace2282 Apr 16, 2024
42484ca
yay its a triangle
JasonGrace2282 Apr 16, 2024
8903025
Cursed!
JasonGrace2282 Apr 16, 2024
fb226b0
Allow support for self.add
JasonGrace2282 Apr 16, 2024
dc205bf
Get it working
JasonGrace2282 Apr 16, 2024
6663612
change test scene
JasonGrace2282 Apr 16, 2024
26dd249
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 16, 2024
9903162
Separate Animation and Scene using SceneBuffer
JasonGrace2282 Apr 9, 2024
e242b5c
Update subclasses
JasonGrace2282 Apr 10, 2024
ed71db6
Fix bugs with not clearing buffer
JasonGrace2282 Apr 10, 2024
156712f
remove useless clear in scene.py'
JasonGrace2282 Apr 10, 2024
0cdaf2b
fixes
JasonGrace2282 Apr 10, 2024
ae88c73
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 10, 2024
96fae7e
Add Scene.replace functionality
JasonGrace2282 Apr 13, 2024
25fa9f3
Make :class:`.Animation` explicitly implement `AnimationProtocol`
JasonGrace2282 Apr 13, 2024
c845965
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 16, 2024
133adf7
fix a bug with animation restructuring
JasonGrace2282 Apr 16, 2024
eb320b7
fix succession
JasonGrace2282 Apr 17, 2024
a0036ad
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 17, 2024
290e70d
Fix typo in render_manager
JasonGrace2282 Apr 28, 2024
7b69e69
Added window independent resolution rendering
Apr 28, 2024
7a811ee
Merge branch 'render-manager' of github.com:JasonGrace2282/manim into…
Apr 28, 2024
64521c2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 28, 2024
755428d
Whops ?
Apr 28, 2024
47579b6
Merge branch 'render-manager' of github.com:JasonGrace2282/manim into…
Apr 28, 2024
db3d8ec
Who needs window names anyway
Apr 28, 2024
db52084
fixed transform animation
Apr 29, 2024
5449632
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 29, 2024
92fec8e
Remove printing of animation buffer
JasonGrace2282 Apr 29, 2024
b9e87af
Lint, remove unused imports
JasonGrace2282 Apr 30, 2024
d5004fe
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 30, 2024
5d010d3
Removed useless reading from the gpu
MrDiver Apr 30, 2024
69cce72
Merge branch 'render-manager' of github.com:JasonGrace2282/manim into…
MrDiver Apr 30, 2024
7c7ecab
Fixed broken interp function in opengl_vectorized mobject which used …
MrDiver Apr 30, 2024
97fabab
Fixed TracedPath
MrDiver Apr 30, 2024
8c68b4e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 30, 2024
27fae83
Whops
MrDiver Apr 30, 2024
d7d13d9
Merge branch 'render-manager' of github.com:JasonGrace2282/manim into…
MrDiver Apr 30, 2024
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
7 changes: 5 additions & 2 deletions example_scenes/new_test_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from manim.animation.creation import Create, DrawBorderThenFill, Write
from manim.animation.fading import FadeIn
from manim.animation.transform import Transform
from manim.camera.camera import OpenGLCameraFrame
from manim.camera.camera import Camera
from manim.constants import LEFT, OUT, RIGHT, UP
from manim.mobject.geometry.arc import Circle
from manim.mobject.geometry.polygram import Square
Expand All @@ -39,6 +39,7 @@ def progress_through_animations(animations):
win = Window(
width=1920,
height=1080,
fullscreen=True,
vsync=True,
config=Config(double_buffer=True, samples=0),
)
Expand Down Expand Up @@ -70,7 +71,7 @@ def progress_through_animations(animations):
clock_mobject = DecimalNumber(0.0).shift(4 * LEFT + 2.5 * UP)
clock_mobject.fix_in_frame()

camera = OpenGLCameraFrame()
camera = Camera()
camera.save_state()
# renderer.init_camera(camera)

Expand Down Expand Up @@ -151,6 +152,8 @@ def on_resize(width, height):
if not is_finished:
if virtual_time >= run_time:
animation.finish()
buffer = str(animation.buffer)
print(f"{buffer = }")
has_finished = True
else:
animation.update_mobjects(dt)
Expand Down
13 changes: 13 additions & 0 deletions example_scenes/test_new_rendering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from manim import *


class Test(Scene):
def construct(self) -> None:
s = Square()
c = Circle()
st = Star(color=YELLOW, fill_color=YELLOW)
self.play(Succession(*[Create(x) for x in VGroup(s, c, st).arrange()]))


with tempconfig({"renderer": "opengl", "preview": True, "parallel": False}):
Test().render()
2 changes: 0 additions & 2 deletions manim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
from .animation.transform_matching_parts import *
from .animation.updaters.mobject_update_utils import *
from .animation.updaters.update import *
from .camera.cairo_camera import *
from .constants import *
from .mobject.frame import *
from .mobject.geometry.arc import *
Expand Down Expand Up @@ -73,7 +72,6 @@
from .mobject.types.vectorized_mobject import *
from .mobject.value_tracker import *
from .mobject.vector_field import *
from .renderer.cairo_renderer import *
from .scene.scene import *
from .scene.scene_file_writer import *
from .scene.section import *
Expand Down
10 changes: 10 additions & 0 deletions manim/_config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ class MyScene(Scene):
"write_to_movie",
"zero_pad",
"force_window",
"parallel",
}

def __init__(self) -> None:
Expand Down Expand Up @@ -582,6 +583,7 @@ def digest_parser(self, parser: configparser.ConfigParser) -> ManimConfig:
"use_projection_stroke_shaders",
"enable_wireframe",
"force_window",
"parallel",
]:
setattr(self, key, parser["CLI"].getboolean(key, fallback=False))

Expand Down Expand Up @@ -995,6 +997,14 @@ def format(self, val: str) -> None:
"Output format set as webm, this can be slower than other formats",
)

@property
def in_parallel(self) -> None:
return self._d["parallel"]

@in_parallel.setter
def in_parallel(self, val: bool) -> None:
self._set_boolean("parallel", val)

ffmpeg_loglevel = property(
lambda self: self._d["ffmpeg_loglevel"],
lambda self, val: self._set_from_list(
Expand Down
118 changes: 50 additions & 68 deletions manim/animation/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,23 @@
from ..mobject.mobject import Mobject
from ..mobject.opengl import opengl_mobject
from ..utils.rate_functions import linear, smooth
from .protocol import AnimationProtocol
from .scene_buffer import SceneBuffer

__all__ = ["Animation", "Wait", "override_animation"]


from copy import deepcopy
from typing import TYPE_CHECKING, Callable, Iterable, Sequence
from typing import TYPE_CHECKING, Callable, Iterable, Sequence, TypeVar

if TYPE_CHECKING:
from manim.scene.scene import Scene
from typing_extensions import Self


DEFAULT_ANIMATION_RUN_TIME: float = 1.0
DEFAULT_ANIMATION_LAG_RATIO: float = 0.0


class Animation:
class Animation(AnimationProtocol):
"""An animation.

Animations have a fixed time span.
Expand Down Expand Up @@ -127,17 +128,17 @@ def __new__(

def __init__(
self,
mobject: Mobject | None,
mobject: OpenGLMobject | None,
lag_ratio: float = DEFAULT_ANIMATION_LAG_RATIO,
run_time: float = DEFAULT_ANIMATION_RUN_TIME,
rate_func: Callable[[float], float] = smooth,
reverse_rate_function: bool = False,
name: str = None,
remover: bool = False, # remove a mobject from the screen?
name: str | None = None,
remover: bool = False, # remove a mobject from the screen at end of animation
suspend_mobject_updating: bool = True,
introducer: bool = False,
*,
_on_finish: Callable[[], None] = lambda _: None,
_on_finish: Callable[[SceneBuffer], object] = lambda _: None,
**kwargs,
) -> None:
self._typecheck_input(mobject)
Expand All @@ -149,15 +150,15 @@ def __init__(
self.introducer: bool = introducer
self.suspend_mobject_updating: bool = suspend_mobject_updating
self.lag_ratio: float = lag_ratio
self._on_finish: Callable[[Scene], None] = _on_finish
if config["renderer"] == RendererType.OPENGL:
self.starting_mobject: OpenGLMobject = OpenGLMobject()
self.mobject: OpenGLMobject = (
mobject if mobject is not None else OpenGLMobject()
)
else:
self.starting_mobject: Mobject = Mobject()
self.mobject: Mobject = mobject if mobject is not None else Mobject()
self._on_finish = _on_finish

self.buffer = SceneBuffer()
self.apply_buffer = False # ask scene to apply buffer

self.starting_mobject: OpenGLMobject = OpenGLMobject()
self.mobject: OpenGLMobject = (
mobject if mobject is not None else OpenGLMobject()
)
if kwargs:
logger.debug("Animation received extra kwargs: %s", kwargs)

Expand All @@ -169,7 +170,7 @@ def __init__(
),
)

def _typecheck_input(self, mobject: Mobject | None) -> None:
def _typecheck_input(self, mobject: Mobject | OpenGLMobject | None) -> None:
if mobject is None:
logger.debug("Animation with empty mobject")
elif not isinstance(mobject, (Mobject, OpenGLMobject)):
Expand Down Expand Up @@ -213,10 +214,12 @@ def begin(self) -> None:
self.mobject.suspend_updating()
self.interpolate(0)

# TODO: Figure out a way to check
# if self.mobject in scene.get_mobject_family
if self.is_introducer():
self.buffer.add(self.mobject)

def finish(self) -> None:
# TODO: begin and finish should require a scene as parameter.
# That way Animation.clean_up_from_screen and Scene.add_mobjects_from_animations
# could be removed as they fulfill basically the same purpose.
"""Finish the animation.

This method gets called when the animation is over.
Expand All @@ -226,39 +229,9 @@ def finish(self) -> None:
if self.suspend_mobject_updating and self.mobject is not None:
self.mobject.resume_updating()

def clean_up_from_scene(self, scene: Scene) -> None:
"""Clean up the :class:`~.Scene` after finishing the animation.

This includes to :meth:`~.Scene.remove` the Animation's
:class:`~.Mobject` if the animation is a remover.

Parameters
----------
scene
The scene the animation should be cleaned up from.
"""
self._on_finish(scene)
self._on_finish(self.buffer)
if self.is_remover():
scene.remove(self.mobject)

def _setup_scene(self, scene: Scene) -> None:
"""Setup up the :class:`~.Scene` before starting the animation.

This includes to :meth:`~.Scene.add` the Animation's
:class:`~.Mobject` if the animation is an introducer.

Parameters
----------
scene
The scene the animation should be cleaned up from.
"""
if scene is None:
return
if (
self.is_introducer()
and self.mobject not in scene.get_mobject_family_members()
):
scene.add(self.mobject)
self.buffer.remove(self.mobject)

def create_starting_mobject(self) -> Mobject:
# Keep track of where the mobject starts
Expand Down Expand Up @@ -294,6 +267,17 @@ def update_mobjects(self, dt: float) -> None:
for mob in self.get_all_mobjects_to_update():
mob.update(dt)

def process_subanimation_buffer(self, buffer: SceneBuffer):
"""
This is used in animations that are proxies around
other animations, like :class:`.AnimationGroup`
"""
self.buffer.remove(*buffer.to_remove)
for to_replace_pairs in buffer.to_replace:
self.buffer.replace(*to_replace_pairs)
self.buffer.add(*buffer.to_add)
buffer.clear()

def get_all_mobjects_to_update(self) -> list[Mobject]:
"""Get all mobjects to be updated during the animation.

Expand All @@ -305,9 +289,9 @@ def get_all_mobjects_to_update(self) -> list[Mobject]:
# The surrounding scene typically handles
# updating of self.mobject. Besides, in
# most cases its updating is suspended anyway
return list(filter(lambda m: m is not self.mobject, self.get_all_mobjects()))
return [m for m in self.get_all_mobjects() if m is not self.mobject]

def copy(self) -> Animation:
def copy(self) -> Self:
"""Create a copy of the animation.

Returns
Expand Down Expand Up @@ -343,7 +327,7 @@ def interpolate_mobject(self, alpha: float) -> None:
is completed. For example, alpha-values of 0, 0.5, and 1 correspond
to the animation being completed 0%, 50%, and 100%, respectively.
"""
families = list(self.get_all_families_zipped())
families = tuple(self.get_all_families_zipped())
for i, mobs in enumerate(families):
sub_alpha = self.get_sub_alpha(alpha, i, len(families))
self.interpolate_submobject(*mobs, sub_alpha)
Expand All @@ -356,7 +340,7 @@ def interpolate_submobject(
alpha: float,
) -> Animation:
# Typically implemented by subclass
pass
raise NotImplementedError()

def get_sub_alpha(self, alpha: float, index: int, num_submobjects: int) -> float:
"""Get the animation progress of any submobjects subanimation.
Expand Down Expand Up @@ -422,7 +406,7 @@ def get_run_time(self) -> float:
def set_rate_func(
self,
rate_func: Callable[[float], float],
) -> Animation:
) -> Self:
"""Set the rate function of the animation.

Parameters
Expand Down Expand Up @@ -451,7 +435,7 @@ def get_rate_func(
"""
return self.rate_func

def set_name(self, name: str) -> Animation:
def set_name(self, name: str) -> Self:
"""Set the name of the animation.

Parameters
Expand Down Expand Up @@ -489,7 +473,9 @@ def is_introducer(self) -> bool:


def prepare_animation(
anim: Animation | mobject._AnimationBuilder,
anim: AnimationProtocol
| mobject._AnimationBuilder
| opengl_mobject._AnimationBuilder,
) -> Animation:
r"""Returns either an unchanged animation, or the animation built
from a passed animation factory.
Expand Down Expand Up @@ -517,10 +503,7 @@ def prepare_animation(
TypeError: Object 42 cannot be converted to an animation

"""
if isinstance(anim, mobject._AnimationBuilder):
return anim.build()

if isinstance(anim, opengl_mobject._AnimationBuilder):
if isinstance(anim, (mobject._AnimationBuilder, opengl_mobject._AnimationBuilder)):
return anim.build()

if isinstance(anim, Animation):
Expand Down Expand Up @@ -576,9 +559,6 @@ def begin(self) -> None:
def finish(self) -> None:
pass

def clean_up_from_scene(self, scene: Scene) -> None:
pass

def update_mobjects(self, dt: float) -> None:
pass

Expand Down Expand Up @@ -625,7 +605,9 @@ def construct(self):

"""

def decorator(func):
_F = TypeVar("_F", bound=Callable)

def decorator(func: _F) -> _F:
func._override_animation = animation_class
return func

Expand Down
Loading
Loading