summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/engine.cpp8
-rw-r--r--core/config/engine.h4
-rw-r--r--core/core_bind.cpp6
-rw-r--r--core/core_bind.h3
-rw-r--r--doc/classes/AnimationPlayer.xml5
-rw-r--r--doc/classes/Engine.xml6
-rw-r--r--main/main.cpp17
-rw-r--r--scene/animation/animation_player.cpp19
-rw-r--r--scene/animation/animation_player.h4
-rw-r--r--servers/movie_writer/movie_writer.cpp26
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("----------------");
}