Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode. * It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time). * If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult. * Implements a simple, default MJPEG writer. This new features has two main use cases, which have high demand: * Saving game videos in high quality and ensuring the frame rate is *completely* stable, always. * Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this). **Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly). Usage: $ godot --write-movie movie.avi [scene_file.tscn] Missing: * Options for configuring video writing via GLOBAL_DEF * UI Menu for launching with this mode from the editor. * Add to list of command line options. * Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
This commit is contained in:
@@ -2342,6 +2342,20 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
|
||||
return;
|
||||
}
|
||||
|
||||
String write_movie_file;
|
||||
if (write_movie_button->is_pressed()) {
|
||||
if (p_current && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->has_meta("movie_file")) {
|
||||
// If the scene file has a movie_file metadata set, use this as file. Quick workaround if you want to have multiple scenes that write to multiple movies.
|
||||
write_movie_file = get_tree()->get_edited_scene_root()->get_meta("movie_file");
|
||||
} else {
|
||||
write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
|
||||
}
|
||||
if (write_movie_file == String()) {
|
||||
show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the 'Editor/Movie Writer' category.\nAlternatively, for running single scenes, a 'movie_path' metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
play_button->set_pressed(false);
|
||||
play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
|
||||
play_scene_button->set_pressed(false);
|
||||
@@ -2405,7 +2419,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
|
||||
}
|
||||
|
||||
EditorDebuggerNode::get_singleton()->start();
|
||||
Error error = editor_run.run(run_filename);
|
||||
Error error = editor_run.run(run_filename, write_movie_file);
|
||||
if (error != OK) {
|
||||
EditorDebuggerNode::get_singleton()->stop();
|
||||
show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
|
||||
@@ -2788,6 +2802,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
|
||||
case RUN_SETTINGS: {
|
||||
project_settings_editor->popup_project_settings();
|
||||
} break;
|
||||
case RUN_WRITE_MOVIE: {
|
||||
_update_write_movie_icon();
|
||||
} break;
|
||||
case FILE_INSTALL_ANDROID_SOURCE: {
|
||||
if (p_confirmed) {
|
||||
export_template_manager->install_android_template();
|
||||
@@ -4949,6 +4966,14 @@ String EditorNode::get_run_playing_scene() const {
|
||||
return run_filename;
|
||||
}
|
||||
|
||||
void EditorNode::_update_write_movie_icon() {
|
||||
if (write_movie_button->is_pressed()) {
|
||||
write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWriteEnabled"), SNAME("EditorIcons")));
|
||||
} else {
|
||||
write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::_immediate_dialog_confirmed() {
|
||||
immediate_dialog_confirmed = true;
|
||||
}
|
||||
@@ -6704,6 +6729,23 @@ EditorNode::EditorNode() {
|
||||
ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R);
|
||||
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
|
||||
|
||||
write_movie_button = memnew(Button);
|
||||
write_movie_button->set_flat(true);
|
||||
write_movie_button->set_toggle_mode(true);
|
||||
play_hb->add_child(write_movie_button);
|
||||
write_movie_button->set_pressed(false);
|
||||
write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
|
||||
write_movie_button->set_focus_mode(Control::FOCUS_NONE);
|
||||
write_movie_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_WRITE_MOVIE));
|
||||
write_movie_button->set_tooltip(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
|
||||
// Restore these values to something more useful so it ignores the theme
|
||||
write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.4));
|
||||
write_movie_button->add_theme_color_override("icon_pressed_color", Color(1, 1, 1, 1));
|
||||
write_movie_button->add_theme_color_override("icon_hover_color", Color(1.2, 1.2, 1.2, 0.4));
|
||||
write_movie_button->add_theme_color_override("icon_hover_pressed_color", Color(1.2, 1.2, 1.2, 1));
|
||||
write_movie_button->add_theme_color_override("icon_focus_color", Color(1, 1, 1, 1));
|
||||
write_movie_button->add_theme_color_override("icon_disabled_color", Color(1, 1, 1, 0.4));
|
||||
|
||||
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
|
||||
menu_hb->add_child(right_menu_hb);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user