99import types
1010
1111from . import constants , logger , console , file_writer_config
12- from .config .config import args
12+ from .config .config import camera_config , args
1313from .config import cfg_subcmds
14+ from .utils .module_ops import (
15+ get_module ,
16+ get_scene_classes_from_module ,
17+ get_scenes_to_render ,
18+ )
1419from .scene .scene import Scene
1520from .utils .sounds import play_error_sound , play_finish_sound
1621from .utils .file_ops import open_file as open_media_file
17- from . import constants
22+ from .grpc . impl import frame_server_impl
1823
1924
2025def open_file_if_needed (file_writer ):
@@ -50,104 +55,6 @@ def open_file_if_needed(file_writer):
5055 sys .stdout = curr_stdout
5156
5257
53- def is_child_scene (obj , module ):
54- return (
55- inspect .isclass (obj )
56- and issubclass (obj , Scene )
57- and obj != Scene
58- and obj .__module__ .startswith (module .__name__ )
59- )
60-
61-
62- def prompt_user_for_choice (scene_classes ):
63- num_to_class = {}
64- for count , scene_class in enumerate (scene_classes ):
65- count += 1 # start with 1 instead of 0
66- name = scene_class .__name__
67- console .print (f"{ count } : { name } " , style = "logging.level.info" )
68- num_to_class [count ] = scene_class
69- try :
70- user_input = console .input (
71- f"[log.message] { constants .CHOOSE_NUMBER_MESSAGE } [/log.message]"
72- )
73- return [
74- num_to_class [int (num_str )]
75- for num_str in re .split (r"\s*,\s*" , user_input .strip ())
76- ]
77- except KeyError :
78- logger .error (constants .INVALID_NUMBER_MESSAGE )
79- sys .exit (2 )
80- except EOFError :
81- sys .exit (1 )
82-
83-
84- def get_scenes_to_render (scene_classes ):
85- if not scene_classes :
86- logger .error (constants .NO_SCENE_MESSAGE )
87- return []
88- if file_writer_config ["write_all" ]:
89- return scene_classes
90- result = []
91- for scene_name in file_writer_config ["scene_names" ]:
92- found = False
93- for scene_class in scene_classes :
94- if scene_class .__name__ == scene_name :
95- result .append (scene_class )
96- found = True
97- break
98- if not found and (scene_name != "" ):
99- logger .error (constants .SCENE_NOT_FOUND_MESSAGE .format (scene_name ))
100- if result :
101- return result
102- return (
103- [scene_classes [0 ]]
104- if len (scene_classes ) == 1
105- else prompt_user_for_choice (scene_classes )
106- )
107-
108-
109- def get_scene_classes_from_module (module ):
110- return [
111- member [1 ]
112- for member in inspect .getmembers (module , lambda x : is_child_scene (x , module ))
113- ]
114-
115-
116- def get_module (file_name ):
117- if file_name == "-" :
118- # Since this feature is used for rapid testing, using Scene Caching would be a
119- # hindrance in this case.
120- file_writer_config ["disable_caching" ] = True
121- module = types .ModuleType ("input_scenes" )
122- logger .info (
123- "Enter the animation's code & end with an EOF (CTRL+D on Linux/Unix, CTRL+Z on Windows):"
124- )
125- code = sys .stdin .read ()
126- if not code .startswith ("from manim import" ):
127- logger .warning (
128- "Didn't find an import statement for Manim. Importing automatically..."
129- )
130- code = "from manim import *\n " + code
131- logger .info ("Rendering animation from typed code..." )
132- try :
133- exec (code , module .__dict__ )
134- return module
135- except Exception as e :
136- logger .error (f"Failed to render scene: { str (e )} " )
137- sys .exit (2 )
138- else :
139- if os .path .exists (file_name ):
140- if file_name [- 3 :] != ".py" :
141- raise Exception (f"{ file_name } is not a valid Manim python script." )
142- module_name = file_name [:- 3 ].replace (os .sep , "." ).split ("." )[- 1 ]
143- spec = importlib .util .spec_from_file_location (module_name , file_name )
144- module = importlib .util .module_from_spec (spec )
145- spec .loader .exec_module (module )
146- return module
147- else :
148- raise FileNotFoundError (f"{ file_name } not found" )
149-
150-
15158def main ():
15259 if hasattr (args , "subcommands" ):
15360 if "cfg" in args .subcommands :
@@ -169,15 +76,19 @@ def main():
16976 sound_on = file_writer_config ["sound" ]
17077 for SceneClass in scene_classes_to_render :
17178 try :
172- # By invoking, this renders the full scene
173- scene = SceneClass ()
174- open_file_if_needed (scene .file_writer )
175- if sound_on :
176- play_finish_sound ()
79+ if camera_config ["use_js_renderer" ]:
80+ frame_server_impl .get (SceneClass ).start ()
81+ else :
82+ scene = SceneClass ()
83+ scene .render ()
84+ open_file_if_needed (scene .file_writer )
85+ if sound_on :
86+ play_finish_sound ()
17787 except Exception :
17888 print ("\n \n " )
17989 traceback .print_exc ()
18090 print ("\n \n " )
91+ if not camera_config ["use_js_renderer" ]:
18192 if sound_on :
18293 play_error_sound ()
18394
0 commit comments