Ver Fonte

Merge pull request #62414 from Calinou/movie-maker-add-quit-on-end

Rémi Verschelde há 3 anos atrás
pai
commit
1e4b38fc5d

+ 8 - 0
core/config/engine.cpp

@@ -246,6 +246,14 @@ void Engine::get_singletons(List<Singleton> *p_singletons) {
 	}
 }
 
+String Engine::get_write_movie_path() const {
+	return write_movie_path;
+}
+
+void Engine::set_write_movie_path(const String &p_path) {
+	write_movie_path = p_path;
+}
+
 void Engine::set_shader_cache_path(const String &p_path) {
 	shader_cache_path = p_path;
 }

+ 4 - 0
core/config/engine.h

@@ -76,6 +76,7 @@ private:
 
 	static Engine *singleton;
 
+	String write_movie_path;
 	String shader_cache_path;
 
 public:
@@ -138,6 +139,9 @@ public:
 	Dictionary get_license_info() const;
 	String get_license_text() const;
 
+	void set_write_movie_path(const String &p_path);
+	String get_write_movie_path() const;
+
 	void set_shader_cache_path(const String &p_path);
 	String get_shader_cache_path() const;
 

+ 6 - 0
core/core_bind.cpp

@@ -2290,6 +2290,10 @@ bool Engine::is_editor_hint() const {
 	return ::Engine::get_singleton()->is_editor_hint();
 }
 
+String Engine::get_write_movie_path() const {
+	return ::Engine::get_singleton()->get_write_movie_path();
+}
+
 void Engine::set_print_error_messages(bool p_enabled) {
 	::Engine::get_singleton()->set_print_error_messages(p_enabled);
 }
@@ -2339,6 +2343,8 @@ void Engine::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("is_editor_hint"), &Engine::is_editor_hint);
 
+	ClassDB::bind_method(D_METHOD("get_write_movie_path"), &Engine::get_write_movie_path);
+
 	ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &Engine::set_print_error_messages);
 	ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &Engine::is_printing_error_messages);
 

+ 3 - 0
core/core_bind.h

@@ -676,6 +676,9 @@ public:
 	void set_editor_hint(bool p_enabled);
 	bool is_editor_hint() const;
 
+	// `set_write_movie_path()` is not exposed to the scripting API as changing it at run-time has no effect.
+	String get_write_movie_path() const;
+
 	void set_print_error_messages(bool p_enabled);
 	bool is_printing_error_messages() const;
 

+ 5 - 0
doc/classes/AnimationPlayer.xml

@@ -220,6 +220,10 @@
 		<member name="method_call_mode" type="int" setter="set_method_call_mode" getter="get_method_call_mode" enum="AnimationPlayer.AnimationMethodCallMode" default="0">
 			The call mode to use for Call Method tracks.
 		</member>
+		<member name="movie_quit_on_finish" type="bool" setter="set_movie_quit_on_finish_enabled" getter="is_movie_quit_on_finish_enabled" default="false">
+			If [code]true[/code] and the engine is running in Movie Maker mode (see [MovieWriter]), exits the engine with [method SceneTree.quit] as soon as an animation is done playing in this [AnimationPlayer]. A message is printed when the engine quits for this reason.
+			[b]Note:[/b] This obeys the same logic as the [signal animation_finished] signal, so it will not quit the engine if the animation is set to be looping.
+		</member>
 		<member name="playback_active" type="bool" setter="set_active" getter="is_active">
 			If [code]true[/code], updates animations in response to process-related notifications.
 		</member>
@@ -253,6 +257,7 @@
 			<argument index="0" name="anim_name" type="StringName" />
 			<description>
 				Notifies when an animation finished playing.
+				[b]Note:[/b] This signal is not emitted if an animation is looping.
 			</description>
 		</signal>
 		<signal name="animation_started">

+ 6 - 0
doc/classes/Engine.xml

@@ -151,6 +151,12 @@
 				[/codeblocks]
 			</description>
 		</method>
+		<method name="get_write_movie_path" qualifiers="const">
+			<return type="String" />
+			<description>
+				Returns the path to the [MovieWriter]'s output file, or an empty string if the engine wasn't started in Movie Maker mode. This path can be absolute or relative depending on how the user specified it.
+			</description>
+		</method>
 		<method name="has_singleton" qualifiers="const">
 			<return type="bool" />
 			<argument index="0" name="name" type="StringName" />

+ 8 - 9
main/main.cpp

@@ -181,7 +181,6 @@ static bool debug_navigation = false;
 static int frame_delay = 0;
 static bool disable_render_loop = false;
 static int fixed_fps = -1;
-static String write_movie_path;
 static MovieWriter *movie_writer = nullptr;
 static bool disable_vsync = false;
 static bool print_fps = false;
@@ -1162,7 +1161,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 			}
 		} else if (I->get() == "--write-movie") {
 			if (I->next()) {
-				write_movie_path = I->next()->get();
+				Engine::get_singleton()->set_write_movie_path(I->next()->get());
 				N = I->next()->next();
 				if (fixed_fps == -1) {
 					fixed_fps = 60;
@@ -1512,7 +1511,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		audio_driver_idx = 0;
 	}
 
-	if (write_movie_path != String()) {
+	if (Engine::get_singleton()->get_write_movie_path() != String()) {
 		// Always use dummy driver for audio driver (which is last), also in no threaded mode.
 		audio_driver_idx = AudioDriverManager::get_driver_count() - 1;
 		AudioDriverDummy::get_dummy_singleton()->set_use_threads(false);
@@ -1609,7 +1608,7 @@ error:
 	display_driver = "";
 	audio_driver = "";
 	tablet_driver = "";
-	write_movie_path = "";
+	Engine::get_singleton()->set_write_movie_path(String());
 	project_path = "";
 
 	args.clear();
@@ -1784,11 +1783,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 		rendering_server->set_print_gpu_profile(true);
 	}
 
-	if (write_movie_path != String()) {
-		movie_writer = MovieWriter::find_writer_for_file(write_movie_path);
+	if (Engine::get_singleton()->get_write_movie_path() != String()) {
+		movie_writer = MovieWriter::find_writer_for_file(Engine::get_singleton()->get_write_movie_path());
 		if (movie_writer == nullptr) {
-			ERR_PRINT("Can't find movie writer for file type, aborting: " + write_movie_path);
-			write_movie_path = String();
+			ERR_PRINT("Can't find movie writer for file type, aborting: " + Engine::get_singleton()->get_write_movie_path());
+			Engine::get_singleton()->set_write_movie_path(String());
 		}
 	}
 
@@ -2724,7 +2723,7 @@ bool Main::start() {
 	OS::get_singleton()->set_main_loop(main_loop);
 
 	if (movie_writer) {
-		movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, write_movie_path);
+		movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, Engine::get_singleton()->get_write_movie_path());
 	}
 
 	if (minimum_time_msec) {

+ 18 - 1
scene/animation/animation_player.cpp

@@ -1201,11 +1201,15 @@ void AnimationPlayer::_animation_process(double p_delta) {
 					emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
 				}
 			} else {
-				//stop();
 				playing = false;
 				_set_process(false);
 				if (end_notify) {
 					emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned);
+
+					if (movie_quit_on_finish && OS::get_singleton()->has_feature("movie")) {
+						print_line(vformat("Movie Maker mode is enabled. Quitting on animation finish as requested by: %s", get_path()));
+						get_tree()->quit();
+					}
 				}
 			}
 			end_reached = false;
@@ -1892,6 +1896,14 @@ AnimationPlayer::AnimationMethodCallMode AnimationPlayer::get_method_call_mode()
 	return method_call_mode;
 }
 
+void AnimationPlayer::set_movie_quit_on_finish_enabled(bool p_enabled) {
+	movie_quit_on_finish = p_enabled;
+}
+
+bool AnimationPlayer::is_movie_quit_on_finish_enabled() const {
+	return movie_quit_on_finish;
+}
+
 void AnimationPlayer::_set_process(bool p_process, bool p_force) {
 	if (processing == p_process && !p_force) {
 		return;
@@ -2112,6 +2124,9 @@ void AnimationPlayer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
 	ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
 
+	ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
+	ClassDB::bind_method(D_METHOD("is_movie_quit_on_finish_enabled"), &AnimationPlayer::is_movie_quit_on_finish_enabled);
+
 	ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position);
 	ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length);
 
@@ -2133,6 +2148,8 @@ void AnimationPlayer::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode");
 
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "movie_quit_on_finish"), "set_movie_quit_on_finish_enabled", "is_movie_quit_on_finish_enabled");
+
 	ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
 	ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
 	ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));

+ 4 - 0
scene/animation/animation_player.h

@@ -262,6 +262,7 @@ private:
 	bool reset_on_save = true;
 	AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE;
 	AnimationMethodCallMode method_call_mode = ANIMATION_METHOD_CALL_DEFERRED;
+	bool movie_quit_on_finish = false;
 	bool processing = false;
 	bool active = true;
 
@@ -373,6 +374,9 @@ public:
 	void set_method_call_mode(AnimationMethodCallMode p_mode);
 	AnimationMethodCallMode get_method_call_mode() const;
 
+	void set_movie_quit_on_finish_enabled(bool p_enabled);
+	bool is_movie_quit_on_finish_enabled() const;
+
 	void seek(double p_time, bool p_update = false);
 	void seek_delta(double p_time, float p_delta);
 	float get_current_animation_position() const;

+ 26 - 0
servers/movie_writer/movie_writer.cpp

@@ -31,6 +31,7 @@
 #include "movie_writer.h"
 #include "core/config/project_settings.h"
 #include "core/io/dir_access.h"
+#include "core/os/time.h"
 #include "servers/display_server.h"
 
 MovieWriter *MovieWriter::writers[MovieWriter::MAX_WRITERS];
@@ -183,4 +184,29 @@ void MovieWriter::add_frame(const Ref<Image> &p_image) {
 
 void MovieWriter::end() {
 	write_end();
+
+	// Print a report with various statistics.
+	print_line("----------------");
+	String movie_path = Engine::get_singleton()->get_write_movie_path();
+	if (movie_path.is_relative_path()) {
+		// Print absolute path to make finding the file easier,
+		// and to make it clickable in terminal emulators that support this.
+		movie_path = ProjectSettings::get_singleton()->globalize_path("res://").plus_file(movie_path);
+	}
+	print_line(vformat("Done recording movie at path: %s", movie_path));
+
+	const int movie_time_seconds = Engine::get_singleton()->get_frames_drawn() / fps;
+	const String movie_time = vformat("%s:%s:%s",
+			String::num(movie_time_seconds / 3600).pad_zeros(2),
+			String::num((movie_time_seconds % 3600) / 60).pad_zeros(2),
+			String::num(movie_time_seconds % 60).pad_zeros(2));
+
+	const int real_time_seconds = Time::get_singleton()->get_ticks_msec() / 1000;
+	const String real_time = vformat("%s:%s:%s",
+			String::num(real_time_seconds / 3600).pad_zeros(2),
+			String::num((real_time_seconds % 3600) / 60).pad_zeros(2),
+			String::num(real_time_seconds % 60).pad_zeros(2));
+
+	print_line(vformat("%d frames at %d FPS (movie length: %s), recorded in %s (%d%% of real-time speed).", Engine::get_singleton()->get_frames_drawn(), fps, movie_time, real_time, (float(movie_time_seconds) / real_time_seconds) * 100));
+	print_line("----------------");
 }