3b1b-manim/extract_scene.py

221 lines
6.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python
import sys
import getopt
import imp
import itertools as it
2015-06-10 22:00:35 -07:00
import inspect
import traceback
import imp
2017-06-29 14:33:01 +03:00
import os
from helpers import *
from scene import Scene
2016-02-27 18:50:33 -08:00
from camera import Camera
2015-05-07 21:28:02 -07:00
HELP_MESSAGE = """
Usage:
python extract_scene.py <module> [<scene name>]
2015-10-10 18:48:54 -07:00
-p preview in low quality
-s show and save picture of last frame
-w write result to file [this is default if nothing else is stated]
2015-10-10 18:48:54 -07:00
-l use low quality
-m use medium quality
-a run and save every scene in the script, or all args for the given scene
2016-11-15 20:08:28 -08:00
-q don't print progress
2015-05-07 21:28:02 -07:00
"""
SCENE_NOT_FOUND_MESSAGE = """
2015-10-10 18:48:54 -07:00
That scene is not in the script
2015-05-07 21:28:02 -07:00
"""
2015-10-20 21:55:46 -07:00
CHOOSE_NUMBER_MESSAGE = """
Choose number corresponding to desired scene/arguments.
2015-10-20 21:55:46 -07:00
(Use comma separated list for multiple entries)
Choice(s): """
2015-10-10 18:48:54 -07:00
INVALID_NUMBER_MESSAGE = "Fine then, if you don't want to give a valid number I'll just quit"
2015-05-07 21:28:02 -07:00
NO_SCENE_MESSAGE = """
There are no scenes inside that module
"""
2015-10-10 18:48:54 -07:00
def get_configuration(sys_argv):
try:
2017-09-26 17:41:45 -07:00
opts, args = getopt.getopt(sys_argv[1:], 'hlmpwstqao:')
except getopt.GetoptError as err:
print str(err)
sys.exit(2)
2015-10-10 18:48:54 -07:00
config = {
"file" : None,
"scene_name" : "",
"camera_config" : PRODUCTION_QUALITY_CAMERA_CONFIG,
"frame_duration" : PRODUCTION_QUALITY_FRAME_DURATION,
"preview" : False,
"write_to_movie" : False,
2017-05-09 14:21:03 -07:00
"save_frames" : False,
"save_image" : False,
2017-09-26 17:41:45 -07:00
#If -t is passed in (for transparent), this will be RGBA
"saved_image_mode": "RGB",
"quiet" : False,
"write_all" : False,
"output_name" : None,
2015-10-10 18:48:54 -07:00
}
for opt, arg in opts:
if opt == '-h':
2015-05-07 21:28:02 -07:00
print HELP_MESSAGE
return
if opt in ['-l', '-p']:
2016-03-07 19:07:00 -08:00
config["camera_config"] = LOW_QUALITY_CAMERA_CONFIG
config["frame_duration"] = LOW_QUALITY_FRAME_DURATION
if opt == '-p':
2015-10-10 18:48:54 -07:00
config["preview"] = True
2017-05-09 14:21:03 -07:00
config["save_frames"] = True
if opt == '-m':
config["camera_config"] = MEDIUM_QUALITY_CAMERA_CONFIG
config["frame_duration"] = MEDIUM_QUALITY_FRAME_DURATION
if opt == '-w':
config["write_to_movie"] = True
if opt == '-s':
2015-10-10 18:48:54 -07:00
config["save_image"] = True
2017-09-26 17:41:45 -07:00
if opt == '-t':
config["saved_image_mode"] = "RGBA"
if opt in ['-q', '-a']:
2015-10-10 18:48:54 -07:00
config["quiet"] = True
if opt == '-a':
2015-10-10 18:48:54 -07:00
config["write_all"] = True
2017-03-14 15:50:16 -07:00
if opt == '-o':
config["output_name"] = arg
2015-10-10 18:48:54 -07:00
#By default, write to file
actions = ["write_to_movie", "preview", "save_image"]
if not any([config[key] for key in actions]):
config["write_to_movie"] = True
config["skip_animations"] = config["save_image"] and not config["write_to_movie"]
2015-10-10 18:48:54 -07:00
if len(args) == 0:
print HELP_MESSAGE
sys.exit()
2015-12-13 15:41:45 -08:00
config["file"] = args[0]
2015-05-17 15:08:51 -07:00
if len(args) > 1:
config["scene_name"] = args[1]
2015-10-10 18:48:54 -07:00
return config
def handle_scene(scene, **config):
if config["quiet"]:
curr_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
2015-10-10 18:48:54 -07:00
if config["preview"]:
2015-06-13 19:00:23 -07:00
scene.preview()
2015-10-10 18:48:54 -07:00
if config["save_image"]:
if not config["write_all"]:
scene.show_frame()
2017-09-26 17:41:45 -07:00
scene.save_image(mode = config["saved_image_mode"])
2015-06-13 19:00:23 -07:00
2015-10-10 18:48:54 -07:00
if config["quiet"]:
sys.stdout.close()
2015-10-10 18:48:54 -07:00
sys.stdout = curr_stdout
2015-05-07 21:28:02 -07:00
2015-10-10 18:48:54 -07:00
def is_scene(obj):
if not inspect.isclass(obj):
return False
if not issubclass(obj, Scene):
return False
if obj == Scene:
return False
return True
2015-05-07 21:28:02 -07:00
def prompt_user_for_choice(name_to_obj):
num_to_name = {}
2016-08-02 12:26:15 -07:00
names = sorted(name_to_obj.keys())
for count, name in zip(it.count(1), names):
print "%d: %s"%(count, name)
num_to_name[count] = name
2015-10-20 21:55:46 -07:00
try:
user_input = raw_input(CHOOSE_NUMBER_MESSAGE)
2015-10-20 21:55:46 -07:00
return [
name_to_obj[num_to_name[int(num_str)]]
for num_str in user_input.split(",")
2015-10-20 21:55:46 -07:00
]
except:
print INVALID_NUMBER_MESSAGE
sys.exit()
def get_scene_classes(scene_names_to_classes, config):
if len(scene_names_to_classes) == 0:
print NO_SCENE_MESSAGE
return []
if len(scene_names_to_classes) == 1:
return scene_names_to_classes.values()
if config["scene_name"] in scene_names_to_classes:
return [scene_names_to_classes[config["scene_name"]] ]
if config["scene_name"] != "":
print SCENE_NOT_FOUND_MESSAGE
return []
if config["write_all"]:
return scene_names_to_classes.values()
return prompt_user_for_choice(scene_names_to_classes)
2017-06-29 14:33:01 +03:00
def get_module_windows(file_name):
2015-12-13 15:41:45 -08:00
module_name = file_name.replace(".py", "")
2017-06-29 14:33:01 +03:00
last_module = imp.load_module("__init__", *imp.find_module("__init__", ['.']))
2015-12-13 15:41:45 -08:00
for part in module_name.split(os.sep):
2017-06-29 14:33:01 +03:00
load_args = imp.find_module(part, [os.path.dirname(last_module.__file__)])
2015-12-13 15:41:45 -08:00
last_module = imp.load_module(part, *load_args)
return last_module
2017-06-29 14:33:01 +03:00
def get_module_posix(file_name):
module_name = file_name.replace(".py", "")
last_module = imp.load_module(".", *imp.find_module("."))
for part in module_name.split(os.sep):
load_args = imp.find_module(part, last_module.__path__)
last_module = imp.load_module(part, *load_args)
return last_module
def get_module(file_name):
if os.name == 'nt':
return get_module_windows(file_name)
return get_module_posix(file_name)
def main():
2015-10-10 18:48:54 -07:00
config = get_configuration(sys.argv)
2015-12-13 15:41:45 -08:00
module = get_module(config["file"])
scene_names_to_classes = dict(
inspect.getmembers(module, is_scene)
)
config["output_directory"] = os.path.join(
MOVIE_DIR,
config["file"].replace(".py", "")
)
scene_kwargs = dict([
(key, config[key])
for key in [
"camera_config",
"frame_duration",
"skip_animations",
"write_to_movie",
2017-05-09 14:21:03 -07:00
"save_frames",
"output_directory",
]
])
scene_kwargs["name"] = config["output_name"]
for SceneClass in get_scene_classes(scene_names_to_classes, config):
try:
handle_scene(SceneClass(**scene_kwargs), **config)
play_finish_sound()
except:
print "\n\n"
traceback.print_exc()
print "\n\n"
play_error_sound()
if __name__ == "__main__":
main()
2015-05-07 21:28:02 -07:00