summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2022-06-17 00:55:19 +0200
committerreduz <reduzio@gmail.com>2022-06-21 11:28:47 +0200
commit5786516d4d6b517e6a28aec191f944aecf2f544d (patch)
tree8a79324296035a7aa8b7802d610596912b7c1642 /core
parent362f53ff02c381ea94640baa16e84e6f6956efef (diff)
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).
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp1
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/io/image.cpp20
-rw-r--r--core/io/image.h6
-rw-r--r--core/object/object.h1
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h1
7 files changed, 33 insertions, 1 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 12d936d456..570dc675a8 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -41,7 +41,6 @@
#include "core/os/keyboard.h"
#include "core/variant/variant_parser.h"
#include "core/version.h"
-
#include "modules/modules_enabled.gen.h" // For mono.
const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot";
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 4f22c99656..3373f4f1e5 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -588,6 +588,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_OBJECT_TOO_BIG);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_SAVE_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE);
diff --git a/core/io/image.cpp b/core/io/image.cpp
index dfba45c4e9..6585fd9adf 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -81,9 +81,11 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
};
SavePNGFunc Image::save_png_func = nullptr;
+SaveJPGFunc Image::save_jpg_func = nullptr;
SaveEXRFunc Image::save_exr_func = nullptr;
SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
+SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel) {
uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
@@ -2286,6 +2288,14 @@ Error Image::save_png(const String &p_path) const {
return save_png_func(p_path, Ref<Image>((Image *)this));
}
+Error Image::save_jpg(const String &p_path, float p_quality) const {
+ if (save_jpg_func == nullptr) {
+ return ERR_UNAVAILABLE;
+ }
+
+ return save_jpg_func(p_path, Ref<Image>((Image *)this), p_quality);
+}
+
Vector<uint8_t> Image::save_png_to_buffer() const {
if (save_png_buffer_func == nullptr) {
return Vector<uint8_t>();
@@ -2294,6 +2304,14 @@ Vector<uint8_t> Image::save_png_to_buffer() const {
return save_png_buffer_func(Ref<Image>((Image *)this));
}
+Vector<uint8_t> Image::save_jpg_to_buffer(float p_quality) const {
+ if (save_jpg_buffer_func == nullptr) {
+ return Vector<uint8_t>();
+ }
+
+ return save_jpg_buffer_func(Ref<Image>((Image *)this), p_quality);
+}
+
Error Image::save_exr(const String &p_path, bool p_grayscale) const {
if (save_exr_func == nullptr) {
return ERR_UNAVAILABLE;
@@ -3138,6 +3156,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load", "path"), &Image::load);
ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png);
ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer);
+ ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75));
+ ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75));
ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
ClassDB::bind_method(D_METHOD("detect_alpha"), &Image::detect_alpha);
diff --git a/core/io/image.h b/core/io/image.h
index 1025554d51..88b80dc984 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -45,6 +45,8 @@ class Image;
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
+typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
+typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
@@ -54,8 +56,10 @@ class Image : public Resource {
public:
static SavePNGFunc save_png_func;
+ static SaveJPGFunc save_jpg_func;
static SaveEXRFunc save_exr_func;
static SavePNGBufferFunc save_png_buffer_func;
+ static SaveJPGBufferFunc save_jpg_buffer_func;
enum {
MAX_WIDTH = (1 << 24), // force a limit somehow
@@ -281,7 +285,9 @@ public:
Error load(const String &p_path);
Error save_png(const String &p_path) const;
+ Error save_jpg(const String &p_path, float p_quality = 0.75) const;
Vector<uint8_t> save_png_to_buffer() const;
+ Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const;
Error save_exr(const String &p_path, bool p_grayscale) const;
void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
diff --git a/core/object/object.h b/core/object/object.h
index 7cbedd29d9..d0c6c0cb01 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -85,6 +85,7 @@ enum PropertyHint {
PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send
PROPERTY_HINT_NODE_PATH_VALID_TYPES,
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
+ PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_INT_IS_OBJECTID,
PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 327f1c95f2..93477f4288 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -388,6 +388,10 @@ bool OS::has_feature(const String &p_feature) {
return true;
}
+ if (p_feature == "movie") {
+ return _writing_movie;
+ }
+
#ifdef DEBUG_ENABLED
if (p_feature == "debug") {
return true;
diff --git a/core/os/os.h b/core/os/os.h
index 157b8ab992..c6ea9d869a 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -58,6 +58,7 @@ class OS {
bool _allow_layered = false;
bool _stdout_enabled = true;
bool _stderr_enabled = true;
+ bool _writing_movie = false;
CompositeLogger *_logger = nullptr;