2015-10-27 21:00:50 -07:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
2015-05-06 17:58:34 -07:00
|
|
|
import sys
|
2018-01-12 12:37:02 -08:00
|
|
|
# import getopt
|
|
|
|
import argparse
|
2015-05-06 17:58:34 -07:00
|
|
|
import imp
|
|
|
|
import itertools as it
|
2015-06-10 22:00:35 -07:00
|
|
|
import inspect
|
2015-10-11 15:22:47 -07:00
|
|
|
import traceback
|
2015-10-27 21:00:50 -07:00
|
|
|
import imp
|
2017-06-29 14:33:01 +03:00
|
|
|
import os
|
2015-05-06 17:58:34 -07:00
|
|
|
|
2015-10-27 21:00:50 -07:00
|
|
|
from helpers import *
|
|
|
|
from scene import Scene
|
2016-02-27 18:50:33 -08:00
|
|
|
from camera import Camera
|
2015-05-06 17:58:34 -07:00
|
|
|
|
2015-05-07 21:28:02 -07:00
|
|
|
HELP_MESSAGE = """
|
2017-10-05 21:03:30 -05:00
|
|
|
Usage:
|
2016-09-06 16:48:04 -07:00
|
|
|
python extract_scene.py <module> [<scene name>]
|
2015-10-28 16:03:33 -07:00
|
|
|
|
2015-10-10 18:48:54 -07:00
|
|
|
-p preview in low quality
|
|
|
|
-s show and save picture of last frame
|
2015-10-28 16:03:33 -07:00
|
|
|
-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
|
2015-10-28 16:03:33 -07:00
|
|
|
-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
|
2017-12-22 13:00:13 +01:00
|
|
|
-f when writing to a movie file, export the frames in png sequence
|
|
|
|
-t use transperency when exporting images
|
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 = """
|
2015-10-28 16:03:33 -07:00
|
|
|
Choose number corresponding to desired scene/arguments.
|
2015-10-20 21:55:46 -07:00
|
|
|
(Use comma separated list for multiple entries)
|
|
|
|
|
2015-10-28 16:03:33 -07:00
|
|
|
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
|
|
|
|
2015-10-28 16:03:33 -07:00
|
|
|
NO_SCENE_MESSAGE = """
|
|
|
|
There are no scenes inside that module
|
|
|
|
"""
|
|
|
|
|
2015-05-06 17:58:34 -07:00
|
|
|
|
2018-01-12 12:37:02 -08:00
|
|
|
def get_configuration():
|
2015-05-06 17:58:34 -07:00
|
|
|
try:
|
2018-01-12 12:37:02 -08:00
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument(
|
|
|
|
"file", help = "path to file holding the python code for the scene"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"scene_name", help = "Name of the Scene class you want to see"
|
|
|
|
)
|
|
|
|
optional_args = [
|
|
|
|
("-p", "--preview"),
|
|
|
|
("-w", "--write_to_movie"),
|
|
|
|
("-s", "--show_last_frame"),
|
|
|
|
("-l", "--low_quality"),
|
|
|
|
("-m", "--medium_quality"),
|
|
|
|
("-f", "--save_pngs"),
|
|
|
|
("-t", "--transparent"),
|
|
|
|
("-q", "--quiet"),
|
|
|
|
("-a", "--write_all")
|
|
|
|
]
|
|
|
|
for short_arg, long_arg in optional_args:
|
|
|
|
parser.add_argument(short_arg, long_arg, action = "store_true")
|
|
|
|
parser.add_argument("-o", "--output_name")
|
2018-01-18 21:26:57 -08:00
|
|
|
parser.add_argument("-n", "--skip_to_animation_number")
|
2018-01-12 12:37:02 -08:00
|
|
|
args = parser.parse_args()
|
|
|
|
except argparse.ArgumentError as err:
|
2017-10-05 21:03:30 -05:00
|
|
|
print(str(err))
|
2015-05-06 17:58:34 -07:00
|
|
|
sys.exit(2)
|
2015-10-10 18:48:54 -07:00
|
|
|
config = {
|
2018-01-12 12:37:02 -08:00
|
|
|
"file" : args.file,
|
|
|
|
"scene_name" : args.scene_name,
|
|
|
|
"camera_config" : PRODUCTION_QUALITY_CAMERA_CONFIG, #TODO
|
|
|
|
"frame_duration" : PRODUCTION_QUALITY_FRAME_DURATION, #TODO
|
|
|
|
"preview" : args.preview,
|
|
|
|
"write_to_movie" : args.write_to_movie,
|
|
|
|
"save_frames" : args.preview, #Scenes only save frame when previewing
|
|
|
|
"show_last_frame" : args.show_last_frame,
|
|
|
|
"save_pngs" : args.save_pngs,
|
2017-09-26 17:41:45 -07:00
|
|
|
#If -t is passed in (for transparent), this will be RGBA
|
2018-01-12 12:37:02 -08:00
|
|
|
"saved_image_mode": "RGBA" if args.transparent else "RGB",
|
|
|
|
"quiet" : args.quiet or args.write_all,
|
|
|
|
"write_all" : args.write_all,
|
|
|
|
"output_name" : args.output_name,
|
2018-01-18 21:26:57 -08:00
|
|
|
"skip_to_animation_number" : args.skip_to_animation_number,
|
2015-10-10 18:48:54 -07:00
|
|
|
}
|
2018-01-12 12:37:02 -08:00
|
|
|
if args.low_quality or args.preview:
|
|
|
|
config["camera_config"] = LOW_QUALITY_CAMERA_CONFIG
|
|
|
|
config["frame_duration"] = LOW_QUALITY_FRAME_DURATION
|
|
|
|
elif args.medium_quality:
|
|
|
|
config["camera_config"] = MEDIUM_QUALITY_CAMERA_CONFIG
|
|
|
|
config["frame_duration"] = MEDIUM_QUALITY_FRAME_DURATION
|
|
|
|
else:
|
|
|
|
config["camera_config"] = PRODUCTION_QUALITY_CAMERA_CONFIG
|
|
|
|
config["frame_duration"] = PRODUCTION_QUALITY_FRAME_DURATION
|
|
|
|
|
2018-01-18 21:26:57 -08:00
|
|
|
stan = config["skip_to_animation_number"]
|
|
|
|
if stan is not None:
|
|
|
|
config["skip_to_animation_number"] = int(stan)
|
|
|
|
|
2015-10-10 18:48:54 -07:00
|
|
|
#By default, write to file
|
2018-01-12 12:37:02 -08:00
|
|
|
actions = ["write_to_movie", "preview", "show_last_frame"]
|
2015-10-11 15:22:47 -07:00
|
|
|
if not any([config[key] for key in actions]):
|
2017-10-05 21:03:30 -05:00
|
|
|
config["write_to_movie"] = True
|
2018-01-18 21:26:57 -08:00
|
|
|
config["skip_animations"] = any([
|
|
|
|
config["show_last_frame"] and not config["write_to_movie"],
|
|
|
|
config["skip_to_animation_number"],
|
|
|
|
])
|
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")
|
2017-10-05 21:03:30 -05:00
|
|
|
|
2015-10-10 18:48:54 -07:00
|
|
|
if config["preview"]:
|
2015-06-13 19:00:23 -07:00
|
|
|
scene.preview()
|
2018-01-12 12:37:02 -08:00
|
|
|
if config["show_last_frame"]:
|
2015-10-11 15:22:47 -07:00
|
|
|
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"]:
|
2015-10-11 15:22:47 -07:00
|
|
|
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
|
|
|
|
2015-10-28 16:03:33 -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):
|
2017-10-05 21:03:30 -05:00
|
|
|
print("%d: %s"%(count, name))
|
2015-10-28 16:03:33 -07:00
|
|
|
num_to_name[count] = name
|
2015-10-20 21:55:46 -07:00
|
|
|
try:
|
2015-10-28 16:03:33 -07:00
|
|
|
user_input = raw_input(CHOOSE_NUMBER_MESSAGE)
|
2015-10-20 21:55:46 -07:00
|
|
|
return [
|
2015-10-28 16:03:33 -07:00
|
|
|
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:
|
2017-10-05 21:03:30 -05:00
|
|
|
print(INVALID_NUMBER_MESSAGE)
|
2015-10-20 21:55:46 -07:00
|
|
|
sys.exit()
|
|
|
|
|
2015-10-28 16:03:33 -07:00
|
|
|
def get_scene_classes(scene_names_to_classes, config):
|
|
|
|
if len(scene_names_to_classes) == 0:
|
2017-10-05 21:03:30 -05:00
|
|
|
print(NO_SCENE_MESSAGE)
|
2015-10-28 16:03:33 -07:00
|
|
|
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"] != "":
|
2017-10-05 21:03:30 -05:00
|
|
|
print(SCENE_NOT_FOUND_MESSAGE)
|
2015-10-28 16:03:33 -07:00
|
|
|
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
|
2017-10-05 21:03:30 -05:00
|
|
|
|
2017-06-29 14:33:01 +03:00
|
|
|
def get_module(file_name):
|
|
|
|
if os.name == 'nt':
|
|
|
|
return get_module_windows(file_name)
|
|
|
|
return get_module_posix(file_name)
|
|
|
|
|
|
|
|
|
2015-10-27 21:00:50 -07:00
|
|
|
def main():
|
2018-01-12 12:37:02 -08:00
|
|
|
config = get_configuration()
|
2015-12-13 15:41:45 -08:00
|
|
|
module = get_module(config["file"])
|
2015-10-27 21:00:50 -07:00
|
|
|
scene_names_to_classes = dict(
|
|
|
|
inspect.getmembers(module, is_scene)
|
|
|
|
)
|
2017-12-22 13:00:13 +01:00
|
|
|
|
2017-05-09 13:14:08 -07:00
|
|
|
config["output_directory"] = os.path.join(
|
2018-01-12 13:38:25 -08:00
|
|
|
ANIMATIONS_DIR,
|
2017-05-09 13:14:08 -07:00
|
|
|
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",
|
2017-05-09 13:14:08 -07:00
|
|
|
"output_directory",
|
2018-01-18 21:26:57 -08:00
|
|
|
"save_pngs",
|
|
|
|
"skip_to_animation_number",
|
2017-05-09 13:14:08 -07:00
|
|
|
]
|
|
|
|
])
|
2017-12-22 13:00:13 +01:00
|
|
|
|
2017-05-09 14:54:50 -07:00
|
|
|
scene_kwargs["name"] = config["output_name"]
|
2017-12-22 13:00:13 +01:00
|
|
|
if config["save_pngs"]:
|
|
|
|
print "We are going to save a PNG sequence as well..."
|
|
|
|
scene_kwargs["save_pngs"] = True
|
|
|
|
scene_kwargs["pngs_mode"] = config["saved_image_mode"]
|
|
|
|
|
2015-10-28 16:03:33 -07:00
|
|
|
for SceneClass in get_scene_classes(scene_names_to_classes, config):
|
2016-09-06 16:48:04 -07:00
|
|
|
try:
|
|
|
|
handle_scene(SceneClass(**scene_kwargs), **config)
|
|
|
|
play_finish_sound()
|
|
|
|
except:
|
2017-10-05 21:03:30 -05:00
|
|
|
print("\n\n")
|
2016-09-06 16:48:04 -07:00
|
|
|
traceback.print_exc()
|
2017-10-05 21:03:30 -05:00
|
|
|
print("\n\n")
|
2016-09-06 16:48:04 -07:00
|
|
|
play_error_sound()
|
2015-10-11 15:22:47 -07:00
|
|
|
|
|
|
|
|
2015-10-27 21:00:50 -07:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|