diff options
-rw-r--r-- | core/config/engine.cpp | 8 | ||||
-rw-r--r-- | core/config/engine.h | 4 | ||||
-rw-r--r-- | core/core_bind.cpp | 6 | ||||
-rw-r--r-- | core/core_bind.h | 3 | ||||
-rw-r--r-- | doc/classes/AnimationPlayer.xml | 5 | ||||
-rw-r--r-- | doc/classes/Engine.xml | 6 | ||||
-rw-r--r-- | main/main.cpp | 17 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 19 | ||||
-rw-r--r-- | scene/animation/animation_player.h | 4 | ||||
-rw-r--r-- | servers/movie_writer/movie_writer.cpp | 26 |
10 files changed, 88 insertions, 10 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 782d369ae6..44ad4961d9 100644 --- a/core/config/engine.cpp +++ b/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; } diff --git a/core/config/engine.h b/core/config/engine.h index 82e3ee5487..68562643e7 100644 --- a/core/config/engine.h +++ b/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; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 8e776d6f05..e5d5464643 100644 --- a/core/core_bind.cpp +++ b/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); diff --git a/core/core_bind.h b/core/core_bind.h index e222a220f0..f98de81354 100644 --- a/core/core_bind.h +++ b/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; diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 653607610d..b24c439432 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/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"> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 506992e3af..36dfee833b 100644 --- a/doc/classes/Engine.xml +++ b/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" /> diff --git a/main/main.cpp b/main/main.cpp index 73950f3471..ab6c0fbc6a 100644 --- a/main/main.cpp +++ b/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) { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2007dc6405..76bf71387e 100644 --- a/scene/animation/animation_player.cpp +++ b/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"))); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 4dd4b43145..b6d8dab1ed 100644 --- a/scene/animation/animation_player.h +++ b/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; diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp index 93f9f8ea08..40b2b2539e 100644 --- a/servers/movie_writer/movie_writer.cpp +++ b/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("----------------"); } |