Skip to content
Merged
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
5 changes: 4 additions & 1 deletion manim/animation/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,10 @@ def _setup_scene(self, scene: Scene) -> None:
"""
if scene is None:
return
if self.is_introducer():
if (
self.is_introducer()
and self.mobject not in scene.get_mobject_family_members()
):
scene.add(self.mobject)

def create_starting_mobject(self) -> Mobject:
Expand Down
11 changes: 7 additions & 4 deletions manim/renderer/cairo_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,14 @@ def play(self, scene, *args, **kwargs):
{"h": str(self.animations_hashes[:5])},
)

self.file_writer.begin_animation(not self.skip_animations)
scene.begin_animations()

# Save a static image, to avoid rendering non moving objects.
self.static_image = self.save_static_frame_data(scene, scene.static_mobjects)

self.file_writer.begin_animation(not self.skip_animations)
scene.begin_animations()
if scene.is_current_animation_frozen_frame():
self.update_frame(scene)
self.update_frame(scene, mobjects=scene.moving_mobjects)
# self.duration stands for the total run time of all the animations.
# In this case, as there is only a wait, it will be the length of the wait.
self.freeze_current_frame(scene.duration)
Expand Down Expand Up @@ -218,8 +219,8 @@ def save_static_frame_data(
typing.Iterable[Mobject]
the static image computed.
"""
self.static_image = None
if not static_mobjects:
self.static_image = None
return None
self.update_frame(scene, mobjects=static_mobjects)
self.static_image = self.get_frame()
Expand Down Expand Up @@ -258,8 +259,10 @@ def scene_finished(self, scene):
config.save_last_frame = True
config.write_to_movie = False
else:
self.static_image = None
self.update_frame(scene)

if config["save_last_frame"]:
self.static_image = None
self.update_frame(scene)
self.file_writer.save_final_image(self.camera.get_image())
17 changes: 9 additions & 8 deletions manim/scene/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ def add(self, *mobjects):
mobjects = [*mobjects, *self.foreground_mobjects]
self.restructure_mobjects(to_remove=mobjects)
self.mobjects += mobjects
if self.moving_mobjects is not None:
if self.moving_mobjects:
self.restructure_mobjects(
to_remove=mobjects,
mobject_list_name="moving_mobjects",
Expand Down Expand Up @@ -1074,13 +1074,6 @@ def compile_animation_data(self, *animations: Animation, **play_kwargs):
# Static image logic when the wait is static is done by the renderer, not here.
self.animations[0].is_static_wait = True
return None
elif config.renderer != "opengl":
# Paint all non-moving objects onto the screen, so they don't
# have to be rendered every frame
(
self.moving_mobjects,
self.static_mobjects,
) = self.get_moving_and_static_mobjects(self.animations)
self.duration = self.get_run_time(self.animations)
return self

Expand All @@ -1090,6 +1083,14 @@ def begin_animations(self) -> None:
animation._setup_scene(self)
animation.begin()

if config.renderer != "opengl":
# Paint all non-moving objects onto the screen, so they don't
# have to be rendered every frame
(
self.moving_mobjects,
self.static_mobjects,
) = self.get_moving_and_static_mobjects(self.animations)

def is_current_animation_frozen_frame(self) -> bool:
"""Returns whether the current animation produces a static frame (generally a Wait)."""
return (
Expand Down
6 changes: 3 additions & 3 deletions tests/opengl/test_composition_opengl.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from unittest.mock import Mock
from unittest.mock import MagicMock

from manim.animation.animation import Animation, Wait
from manim.animation.composition import AnimationGroup, Succession
Expand All @@ -18,7 +18,7 @@ def test_succession_timing(using_opengl_renderer):
animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)
succession = Succession(animation_1s, animation_4s)
assert succession.get_run_time() == 5.0
succession._setup_scene(Mock())
succession._setup_scene(MagicMock())
succession.begin()
assert succession.active_index == 0
# The first animation takes 20% of the total run time.
Expand Down Expand Up @@ -50,7 +50,7 @@ def test_succession_in_succession_timing(using_opengl_renderer):
)
assert nested_succession.get_run_time() == 5.0
assert succession.get_run_time() == 10.0
succession._setup_scene(Mock())
succession._setup_scene(MagicMock())
succession.begin()
succession.interpolate(0.1)
assert succession.active_index == 0
Expand Down
6 changes: 3 additions & 3 deletions tests/test_composition.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from unittest.mock import Mock
from unittest.mock import MagicMock

import pytest

Expand All @@ -22,7 +22,7 @@ def test_succession_timing():
animation_4s = FadeOut(line, shift=DOWN, run_time=4.0)
succession = Succession(animation_1s, animation_4s)
assert succession.get_run_time() == 5.0
succession._setup_scene(Mock())
succession._setup_scene(MagicMock())
succession.begin()
assert succession.active_index == 0
# The first animation takes 20% of the total run time.
Expand Down Expand Up @@ -54,7 +54,7 @@ def test_succession_in_succession_timing():
)
assert nested_succession.get_run_time() == 5.0
assert succession.get_run_time() == 10.0
succession._setup_scene(Mock())
succession._setup_scene(MagicMock())
succession.begin()
succession.interpolate(0.1)
assert succession.active_index == 0
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
20 changes: 20 additions & 0 deletions tests/test_graphical_units/test_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,23 @@ def test_SpinInFromNothing(scene):
def test_ShrinkToCenter(scene):
square = Square()
scene.play(ShrinkToCenter(square))


@frames_comparison(last_frame=False)
def test_bring_to_back_introducer(scene):
a = Square(color=RED, fill_opacity=1)
b = Square(color=BLUE, fill_opacity=1).shift(RIGHT)
scene.add(a)
scene.bring_to_back(b)
scene.play(FadeIn(b))
scene.wait()


@frames_comparison(last_frame=False)
def test_z_index_introducer(scene):
a = Circle().set_fill(color=RED, opacity=1.0)
scene.add(a)
b = Circle(arc_center=(0.5, 0.5, 0.0), color=GREEN, fill_opacity=1)
b.set_z_index(-1)
scene.play(Create(b))
scene.wait()
1 change: 1 addition & 0 deletions tests/test_graphical_units/test_vector_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ def test_vector_to_coords(scene):
basis = scene.get_basis_vectors()
scene.add(basis)
scene.vector_to_coords(vector=vector)
scene.wait()