|
25 | 25 | from ..utils.hashing import get_hash_from_play_call, get_hash_from_wait_call
|
26 | 26 |
|
27 | 27 |
|
28 |
| -def handle_play_like_call(func): |
29 |
| - """ |
30 |
| - This method is used internally to wrap the |
31 |
| - passed function, into a function that |
32 |
| - actually writes to the video stream. |
33 |
| - Simultaneously, it also adds to the number |
34 |
| - of animations played. |
35 |
| -
|
36 |
| - Parameters |
37 |
| - ---------- |
38 |
| - func : function |
39 |
| - The play() like function that has to be |
40 |
| - written to the video file stream. |
41 |
| -
|
42 |
| - Returns |
43 |
| - ------- |
44 |
| - function |
45 |
| - The play() like function that can now write |
46 |
| - to the video file stream. |
47 |
| - """ |
48 |
| - |
49 |
| - def wrapper(self, *args, **kwargs): |
50 |
| - allow_write = not file_writer_config["skip_animations"] |
51 |
| - if not self.camera.use_js_renderer: |
52 |
| - self.file_writer.begin_animation(allow_write) |
53 |
| - func(self, *args, **kwargs) |
54 |
| - if not self.camera.use_js_renderer: |
55 |
| - self.file_writer.end_animation(allow_write) |
56 |
| - self.num_plays += 1 |
57 |
| - |
58 |
| - return wrapper |
59 |
| - |
60 |
| - |
61 | 28 | class Scene(Container):
|
62 | 29 | """A Scene is the canvas of your animation.
|
63 | 30 |
|
@@ -832,82 +799,6 @@ def update_skipping_status(self):
|
832 | 799 | file_writer_config["skip_animations"] = True
|
833 | 800 | raise EndSceneEarlyException()
|
834 | 801 |
|
835 |
| - def handle_caching_play(func): |
836 |
| - """ |
837 |
| - Decorator that returns a wrapped version of func that will compute the hash of the play invocation. |
838 |
| -
|
839 |
| - The returned function will act according to the computed hash: either skip the animation because it's already cached, or let the invoked function play normally. |
840 |
| -
|
841 |
| - Parameters |
842 |
| - ---------- |
843 |
| - func : Callable[[...], None] |
844 |
| - The play like function that has to be written to the video file stream. Take the same parameters as `scene.play`. |
845 |
| - """ |
846 |
| - |
847 |
| - def wrapper(self, *args, **kwargs): |
848 |
| - self.revert_to_original_skipping_status() |
849 |
| - self.update_skipping_status() |
850 |
| - animations = self.compile_play_args_to_animation_list(*args, **kwargs) |
851 |
| - self.add_mobjects_from_animations(animations) |
852 |
| - if file_writer_config["skip_animations"]: |
853 |
| - logger.debug(f"Skipping animation {self.num_plays}") |
854 |
| - func(self, *args, **kwargs) |
855 |
| - return |
856 |
| - if not file_writer_config["disable_caching"]: |
857 |
| - mobjects_on_scene = self.get_mobjects() |
858 |
| - hash_play = get_hash_from_play_call( |
859 |
| - self, self.camera, animations, mobjects_on_scene |
860 |
| - ) |
861 |
| - self.play_hashes_list.append(hash_play) |
862 |
| - if self.file_writer.is_already_cached(hash_play): |
863 |
| - logger.info( |
864 |
| - f"Animation {self.num_plays} : Using cached data (hash : %(hash_play)s)", |
865 |
| - {"hash_play": hash_play}, |
866 |
| - ) |
867 |
| - file_writer_config["skip_animations"] = True |
868 |
| - else: |
869 |
| - hash_play = "uncached_{:05}".format(self.num_plays) |
870 |
| - self.play_hashes_list.append(hash_play) |
871 |
| - func(self, *args, **kwargs) |
872 |
| - |
873 |
| - return wrapper |
874 |
| - |
875 |
| - def handle_caching_wait(func): |
876 |
| - """ |
877 |
| - Decorator that returns a wrapped version of func that will compute the hash of the wait invocation. |
878 |
| -
|
879 |
| - The returned function will act according to the computed hash: either skip the animation because it's already cached, or let the invoked function play normally. |
880 |
| -
|
881 |
| - Parameters |
882 |
| - ---------- |
883 |
| - func : Callable[[...], None] |
884 |
| - The wait like function that has to be written to the video file stream. Take the same parameters as `scene.wait`. |
885 |
| - """ |
886 |
| - |
887 |
| - def wrapper(self, duration=DEFAULT_WAIT_TIME, stop_condition=None): |
888 |
| - self.revert_to_original_skipping_status() |
889 |
| - self.update_skipping_status() |
890 |
| - if file_writer_config["skip_animations"]: |
891 |
| - logger.debug(f"Skipping wait {self.num_plays}") |
892 |
| - func(self, duration, stop_condition) |
893 |
| - return |
894 |
| - if not file_writer_config["disable_caching"]: |
895 |
| - hash_wait = get_hash_from_wait_call( |
896 |
| - self, self.camera, duration, stop_condition, self.get_mobjects() |
897 |
| - ) |
898 |
| - self.play_hashes_list.append(hash_wait) |
899 |
| - if self.file_writer.is_already_cached(hash_wait): |
900 |
| - logger.info( |
901 |
| - f"Wait {self.num_plays} : Using cached data (hash : {hash_wait})" |
902 |
| - ) |
903 |
| - file_writer_config["skip_animations"] = True |
904 |
| - else: |
905 |
| - hash_wait = "uncached_{:05}".format(self.num_plays) |
906 |
| - self.play_hashes_list.append(hash_wait) |
907 |
| - func(self, duration, stop_condition) |
908 |
| - |
909 |
| - return wrapper |
910 |
| - |
911 | 802 | def begin_animations(self, animations):
|
912 | 803 | """
|
913 | 804 | This method begins the list of animations that is passed,
|
@@ -972,9 +863,54 @@ def finish_animations(self, animations):
|
972 | 863 | else:
|
973 | 864 | self.update_mobjects(0)
|
974 | 865 |
|
975 |
| - @handle_caching_play |
976 |
| - @handle_play_like_call |
| 866 | + def wait(self, duration=DEFAULT_WAIT_TIME, stop_condition=None): |
| 867 | + self.play(duration=duration, stop_condition=stop_condition) |
| 868 | + |
977 | 869 | def play(self, *args, **kwargs):
|
| 870 | + self.cached_play(*args, **kwargs) |
| 871 | + self.num_plays += 1 |
| 872 | + |
| 873 | + def cached_play(self, *args, **kwargs): |
| 874 | + self.revert_to_original_skipping_status() |
| 875 | + self.update_skipping_status() |
| 876 | + animations = self.compile_play_args_to_animation_list(*args, **kwargs) |
| 877 | + self.add_mobjects_from_animations(animations) |
| 878 | + if file_writer_config["skip_animations"]: |
| 879 | + logger.debug(f"Skipping animation {self.num_plays}") |
| 880 | + self.file_writer_wrapped_play(*args, **kwargs) |
| 881 | + return |
| 882 | + if not file_writer_config["disable_caching"]: |
| 883 | + mobjects_on_scene = self.get_mobjects() |
| 884 | + hash_play = get_hash_from_play_call( |
| 885 | + self, self.camera, animations, mobjects_on_scene |
| 886 | + ) |
| 887 | + self.play_hashes_list.append(hash_play) |
| 888 | + if self.file_writer.is_already_cached(hash_play): |
| 889 | + logger.info( |
| 890 | + f"Animation {self.num_plays} : Using cached data (hash : %(hash_play)s)", |
| 891 | + {"hash_play": hash_play}, |
| 892 | + ) |
| 893 | + file_writer_config["skip_animations"] = True |
| 894 | + else: |
| 895 | + hash_play = "uncached_{:05}".format(self.num_plays) |
| 896 | + self.play_hashes_list.append(hash_play) |
| 897 | + self.file_writer_wrapped_play(*args, **kwargs) |
| 898 | + |
| 899 | + def file_writer_wrapped_play(self, *args, **kwargs): |
| 900 | + allow_write = not file_writer_config["skip_animations"] |
| 901 | + self.file_writer.begin_animation(allow_write) |
| 902 | + |
| 903 | + self.play_or_wait(*args, **kwargs) |
| 904 | + |
| 905 | + self.file_writer.end_animation(allow_write) |
| 906 | + |
| 907 | + def play_or_wait(self, *args, **kwargs): |
| 908 | + if "duration" in kwargs: |
| 909 | + self.wait_internal(**kwargs) |
| 910 | + else: |
| 911 | + self.play_internal(*args, **kwargs) |
| 912 | + |
| 913 | + def play_internal(self, *args, **kwargs): |
978 | 914 | """
|
979 | 915 | This method is used to prep the animations for rendering,
|
980 | 916 | apply the arguments and parameters required to them,
|
@@ -1003,6 +939,33 @@ def play(self, *args, **kwargs):
|
1003 | 939 |
|
1004 | 940 | self.finish_animations(self.animations)
|
1005 | 941 |
|
| 942 | + def wait_internal(self, duration=DEFAULT_WAIT_TIME, stop_condition=None): |
| 943 | + self.update_mobjects(dt=0) # Any problems with this? |
| 944 | + self.animations = [] |
| 945 | + self.duration = duration |
| 946 | + self.stop_condition = stop_condition |
| 947 | + self.last_t = 0 |
| 948 | + |
| 949 | + if self.should_update_mobjects(): |
| 950 | + time_progression = self.get_wait_time_progression(duration, stop_condition) |
| 951 | + # TODO, be smart about setting a static image |
| 952 | + # the same way Scene.play does |
| 953 | + for t in time_progression: |
| 954 | + self.update_animation_to_time(t) |
| 955 | + self.update_frame() |
| 956 | + self.add_frame(self.get_frame()) |
| 957 | + if stop_condition is not None and stop_condition(): |
| 958 | + time_progression.close() |
| 959 | + break |
| 960 | + elif self.skip_animations: |
| 961 | + # Do nothing |
| 962 | + return self |
| 963 | + else: |
| 964 | + self.update_frame() |
| 965 | + dt = 1 / self.camera.frame_rate |
| 966 | + self.add_frame(self.get_frame(), num_frames=int(duration / dt)) |
| 967 | + return self |
| 968 | + |
1006 | 969 | def clean_up_animations(self, *animations):
|
1007 | 970 | """
|
1008 | 971 | This method cleans up and removes from the
|
@@ -1073,52 +1036,6 @@ def get_wait_time_progression(self, duration, stop_condition):
|
1073 | 1036 | time_progression.set_description("Waiting {}".format(self.num_plays))
|
1074 | 1037 | return time_progression
|
1075 | 1038 |
|
1076 |
| - @handle_caching_wait |
1077 |
| - @handle_play_like_call |
1078 |
| - def wait(self, duration=DEFAULT_WAIT_TIME, stop_condition=None): |
1079 |
| - """ |
1080 |
| - This method is used to wait, and do nothing to the scene, for some |
1081 |
| - duration. |
1082 |
| - Updaters stop updating, nothing happens. |
1083 |
| -
|
1084 |
| - Parameters |
1085 |
| - ---------- |
1086 |
| - duration : float or int, optional |
1087 |
| - The duration of wait time. |
1088 |
| - stop_condition : |
1089 |
| - A function that determines whether to stop waiting or not. |
1090 |
| -
|
1091 |
| - Returns |
1092 |
| - ------- |
1093 |
| - Scene |
1094 |
| - The scene, after waiting. |
1095 |
| - """ |
1096 |
| - self.update_mobjects(dt=0) # Any problems with this? |
1097 |
| - self.animations = [] |
1098 |
| - self.duration = duration |
1099 |
| - self.stop_condition = stop_condition |
1100 |
| - self.last_t = 0 |
1101 |
| - |
1102 |
| - if self.should_update_mobjects(): |
1103 |
| - time_progression = self.get_wait_time_progression(duration, stop_condition) |
1104 |
| - # TODO, be smart about setting a static image |
1105 |
| - # the same way Scene.play does |
1106 |
| - for t in time_progression: |
1107 |
| - self.update_animation_to_time(t) |
1108 |
| - self.update_frame() |
1109 |
| - self.add_frame(self.get_frame()) |
1110 |
| - if stop_condition is not None and stop_condition(): |
1111 |
| - time_progression.close() |
1112 |
| - break |
1113 |
| - elif self.skip_animations: |
1114 |
| - # Do nothing |
1115 |
| - return self |
1116 |
| - else: |
1117 |
| - self.update_frame() |
1118 |
| - dt = 1 / self.camera.frame_rate |
1119 |
| - self.add_frame(self.get_frame(), num_frames=int(duration / dt)) |
1120 |
| - return self |
1121 |
| - |
1122 | 1039 | def wait_until(self, stop_condition, max_time=60):
|
1123 | 1040 | """
|
1124 | 1041 | Like a wrapper for wait().
|
|
0 commit comments