diff options
Diffstat (limited to 'modules')
71 files changed, 873 insertions, 413 deletions
diff --git a/modules/camera/SCsub b/modules/camera/SCsub index de97724d09..9a6147d433 100644 --- a/modules/camera/SCsub +++ b/modules/camera/SCsub @@ -9,6 +9,6 @@ if env["platform"] == "windows": env_camera.add_source_files(env.modules_sources, "register_types.cpp") env_camera.add_source_files(env.modules_sources, "camera_win.cpp") -elif env["platform"] == "osx": +elif env["platform"] == "macos": env_camera.add_source_files(env.modules_sources, "register_types.cpp") - env_camera.add_source_files(env.modules_sources, "camera_osx.mm") + env_camera.add_source_files(env.modules_sources, "camera_macos.mm") diff --git a/modules/camera/camera_osx.h b/modules/camera/camera_macos.h index b0db844599..badf78f0e8 100644 --- a/modules/camera/camera_osx.h +++ b/modules/camera/camera_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_osx.h */ +/* camera_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,19 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CAMERAOSX_H -#define CAMERAOSX_H +#ifndef CAMERA_MACOS_H +#define CAMERA_MACOS_H ///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!! // If you fix something here, make sure you fix it there as well! #include "servers/camera_server.h" -class CameraOSX : public CameraServer { +class CameraMacOS : public CameraServer { public: - CameraOSX(); + CameraMacOS(); void update_feeds(); }; -#endif /* CAMERAOSX_H */ +#endif /* CAMERA_MACOS_H */ diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_macos.mm index d199c31b2f..0b9696a3e9 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_osx.mm */ +/* camera_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,7 +31,7 @@ ///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!! // If you fix something here, make sure you fix it there as well! -#include "camera_osx.h" +#include "camera_macos.h" #include "servers/camera/camera_feed.h" #import <AVFoundation/AVFoundation.h> @@ -191,9 +191,9 @@ @end ////////////////////////////////////////////////////////////////////////// -// CameraFeedOSX - Subclass for camera feeds in OSX +// CameraFeedMacOS - Subclass for camera feeds in macOS -class CameraFeedOSX : public CameraFeed { +class CameraFeedMacOS : public CameraFeed { private: AVCaptureDevice *device; MyCaptureSession *capture_session; @@ -201,7 +201,7 @@ private: public: AVCaptureDevice *get_device() const; - CameraFeedOSX(); + CameraFeedMacOS(); void set_device(AVCaptureDevice *p_device); @@ -209,16 +209,16 @@ public: void deactivate_feed(); }; -AVCaptureDevice *CameraFeedOSX::get_device() const { +AVCaptureDevice *CameraFeedMacOS::get_device() const { return device; }; -CameraFeedOSX::CameraFeedOSX() { +CameraFeedMacOS::CameraFeedMacOS() { device = nullptr; capture_session = nullptr; }; -void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { +void CameraFeedMacOS::set_device(AVCaptureDevice *p_device) { device = p_device; // get some info @@ -232,7 +232,7 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) { }; }; -bool CameraFeedOSX::activate_feed() { +bool CameraFeedMacOS::activate_feed() { if (capture_session) { // Already recording! } else { @@ -258,7 +258,7 @@ bool CameraFeedOSX::activate_feed() { return true; }; -void CameraFeedOSX::deactivate_feed() { +void CameraFeedMacOS::deactivate_feed() { // end camera capture if we have one if (capture_session) { [capture_session cleanup]; @@ -271,7 +271,7 @@ void CameraFeedOSX::deactivate_feed() { // when devices are connected/disconnected @interface MyDeviceNotifications : NSObject { - CameraOSX *camera_server; + CameraMacOS *camera_server; } @end @@ -282,7 +282,7 @@ void CameraFeedOSX::deactivate_feed() { camera_server->update_feeds(); } -- (id)initForServer:(CameraOSX *)p_server { +- (id)initForServer:(CameraMacOS *)p_server { if (self = [super init]) { camera_server = p_server; @@ -303,9 +303,9 @@ void CameraFeedOSX::deactivate_feed() { MyDeviceNotifications *device_notifications = nil; ////////////////////////////////////////////////////////////////////////// -// CameraOSX - Subclass for our camera server on OSX +// CameraMacOS - Subclass for our camera server on macOS -void CameraOSX::update_feeds() { +void CameraMacOS::update_feeds() { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternalUnknown, AVCaptureDeviceTypeBuiltInWideAngleCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; NSArray *devices = session.devices; @@ -315,7 +315,7 @@ void CameraOSX::update_feeds() { // remove devices that are gone.. for (int i = feeds.size() - 1; i >= 0; i--) { - Ref<CameraFeedOSX> feed = (Ref<CameraFeedOSX>)feeds[i]; + Ref<CameraFeedMacOS> feed = (Ref<CameraFeedMacOS>)feeds[i]; if (![devices containsObject:feed->get_device()]) { // remove it from our array, this will also destroy it ;) @@ -326,14 +326,14 @@ void CameraOSX::update_feeds() { for (AVCaptureDevice *device in devices) { bool found = false; for (int i = 0; i < feeds.size() && !found; i++) { - Ref<CameraFeedOSX> feed = (Ref<CameraFeedOSX>)feeds[i]; + Ref<CameraFeedMacOS> feed = (Ref<CameraFeedMacOS>)feeds[i]; if (feed->get_device() == device) { found = true; }; }; if (!found) { - Ref<CameraFeedOSX> newfeed; + Ref<CameraFeedMacOS> newfeed; newfeed.instantiate(); newfeed->set_device(device); @@ -346,7 +346,7 @@ void CameraOSX::update_feeds() { }; }; -CameraOSX::CameraOSX() { +CameraMacOS::CameraMacOS() { // Find available cameras we have at this time update_feeds(); diff --git a/modules/camera/config.py b/modules/camera/config.py index 8a22751aa7..d2b2542dd9 100644 --- a/modules/camera/config.py +++ b/modules/camera/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return platform == "osx" or platform == "windows" + return platform == "macos" or platform == "windows" def configure(env): diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp index 98a4b5ca1a..40e2224d6b 100644 --- a/modules/camera/register_types.cpp +++ b/modules/camera/register_types.cpp @@ -33,8 +33,8 @@ #if defined(WINDOWS_ENABLED) #include "camera_win.h" #endif -#if defined(OSX_ENABLED) -#include "camera_osx.h" +#if defined(MACOS_ENABLED) +#include "camera_macos.h" #endif void initialize_camera_module(ModuleInitializationLevel p_level) { @@ -45,8 +45,8 @@ void initialize_camera_module(ModuleInitializationLevel p_level) { #if defined(WINDOWS_ENABLED) CameraServer::make_default<CameraWindows>(); #endif -#if defined(OSX_ENABLED) - CameraServer::make_default<CameraOSX>(); +#if defined(MACOS_ENABLED) + CameraServer::make_default<CameraMacOS>(); #endif } diff --git a/modules/denoise/config.py b/modules/denoise/config.py index 3aa840acb0..521115dae5 100644 --- a/modules/denoise/config.py +++ b/modules/denoise/config.py @@ -4,7 +4,7 @@ def can_build(env, platform): # It's also only relevant for tools build and desktop platforms, # as doing lightmap generation and denoising on Android or HTML5 # would be a bit far-fetched. - desktop_platforms = ["linuxbsd", "osx", "windows"] + desktop_platforms = ["linuxbsd", "macos", "windows"] supported_arch = env["bits"] == "64" if env["arch"] == "arm64": supported_arch = False diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index b86e9b386d..4372bb33ba 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -55,7 +55,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l bool in_function_args = false; bool in_member_variable = false; bool in_node_path = false; + bool in_node_ref = false; bool in_annotation = false; + bool in_string_name = false; bool is_hex_notation = false; bool is_bin_notation = false; bool expect_type = false; @@ -165,6 +167,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { region_color = node_path_color; } + if (in_node_ref && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { + region_color = node_ref_color; + } + if (in_string_name && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) { + region_color = string_name_color; + } prev_color = region_color; highlighter_info["color"] = region_color; @@ -387,24 +395,42 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_member_variable = false; } - if (!in_node_path && in_region == -1 && (str[j] == '$' || str[j] == '%')) { + if (!in_node_path && in_region == -1 && (str[j] == '^')) { in_node_path = true; } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { in_node_path = false; } + if (!in_node_ref && in_region == -1 && (str[j] == '$' || str[j] == '%')) { + in_node_ref = true; + } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { + in_node_ref = false; + } + if (!in_annotation && in_region == -1 && str[j] == '@') { in_annotation = true; } else if (in_region != -1 || is_a_symbol) { in_annotation = false; } + if (!in_string_name && in_region == -1 && str[j] == '&') { + in_string_name = true; + } else if (in_region != -1 || is_a_symbol) { + in_string_name = false; + } + if (in_node_path) { next_type = NODE_PATH; color = node_path_color; + } else if (in_node_ref) { + next_type = NODE_REF; + color = node_ref_color; } else if (in_annotation) { next_type = ANNOTATION; color = annotation_color; + } else if (in_string_name) { + next_type = STRING_NAME; + color = string_name_color; } else if (in_keyword) { next_type = KEYWORD; color = keyword_color; @@ -592,17 +618,23 @@ void GDScriptSyntaxHighlighter::_update_cache() { if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) { function_definition_color = Color(0.4, 0.9, 1.0); - node_path_color = Color(0.39, 0.76, 0.35); + node_path_color = Color(0.72, 0.77, 0.49); + node_ref_color = Color(0.39, 0.76, 0.35); annotation_color = Color(1.0, 0.7, 0.45); + string_name_color = Color(1.0, 0.66, 0.72); } else { function_definition_color = Color(0.0, 0.65, 0.73); - node_path_color = Color(0.32, 0.55, 0.29); + node_path_color = Color(0.62, 0.67, 0.39); + node_ref_color = Color(0.32, 0.55, 0.29); annotation_color = Color(0.8, 0.5, 0.25); + string_name_color = Color(0.9, 0.56, 0.62); } EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color); EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_reference_color", node_ref_color); EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/string_name_color", string_name_color); if (text_edit_color_theme == "Default" || godot_2_theme) { EditorSettings::get_singleton()->set_initial_value( "text_editor/theme/highlighting/gdscript/function_definition_color", @@ -613,14 +645,24 @@ void GDScriptSyntaxHighlighter::_update_cache() { node_path_color, true); EditorSettings::get_singleton()->set_initial_value( + "text_editor/theme/highlighting/gdscript/node_reference_color", + node_ref_color, + true); + EditorSettings::get_singleton()->set_initial_value( "text_editor/theme/highlighting/gdscript/annotation_color", annotation_color, true); + EditorSettings::get_singleton()->set_initial_value( + "text_editor/theme/highlighting/gdscript/string_name_color", + string_name_color, + true); } function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color"); node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color"); + node_ref_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_reference_color"); annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color"); + string_name_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/string_name_color"); type_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color"); } diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 92764e3891..7987582f07 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -54,7 +54,9 @@ private: NONE, REGION, NODE_PATH, + NODE_REF, ANNOTATION, + STRING_NAME, SYMBOL, NUMBER, FUNCTION, @@ -74,7 +76,9 @@ private: Color number_color; Color member_color; Color node_path_color; + Color node_ref_color; Color annotation_color; + Color string_name_color; Color type_color; void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index e74314389d..a34bf6ef82 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -278,6 +278,11 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_ GDScriptFunction *func = E.value; MethodInfo mi; mi.name = E.key; + + if (func->is_static()) { + mi.flags |= METHOD_FLAG_STATIC; + } + for (int i = 0; i < func->get_argument_count(); i++) { PropertyInfo arginfo = func->get_argument_type(i); #ifdef TOOLS_ENABLED @@ -870,7 +875,7 @@ Error GDScript::reload(bool p_keep_state) { } // TODO: Show all error messages. _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); - ERR_FAIL_V(ERR_PARSE_ERROR); + return ERR_PARSE_ERROR; } GDScriptAnalyzer analyzer(&parser); @@ -886,7 +891,7 @@ Error GDScript::reload(bool p_keep_state) { _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); e = e->next(); } - ERR_FAIL_V(ERR_PARSE_ERROR); + return ERR_PARSE_ERROR; } bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool(); @@ -904,7 +909,7 @@ Error GDScript::reload(bool p_keep_state) { GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); } _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT); - ERR_FAIL_V(ERR_COMPILATION_FAILED); + return ERR_COMPILATION_FAILED; } else { return err; } diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 033591a0b9..8002c185c7 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -292,7 +292,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) { path = path.plus_file("blender"); #endif -#if defined(OSX_ENABLED) +#if defined(MACOS_ENABLED) if (!FileAccess::exists(path)) { path = path.plus_file("Blender"); } @@ -468,7 +468,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { // Autodetect auto_detected_path = ""; -#if defined(OSX_ENABLED) +#if defined(MACOS_ENABLED) { Vector<String> mdfind_paths; diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp index 1daf2f90a7..1b8911fe72 100644 --- a/modules/gltf/gltf_accessor.cpp +++ b/modules/gltf/gltf_accessor.cpp @@ -30,8 +30,6 @@ #include "gltf_accessor.h" -#include "gltf_document_extension.h" - void GLTFAccessor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view); ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view); @@ -67,7 +65,7 @@ void GLTFAccessor::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "component_type"), "set_component_type", "get_component_type"); // int ADD_PROPERTY(PropertyInfo(Variant::BOOL, "normalized"), "set_normalized", "get_normalized"); // bool ADD_PROPERTY(PropertyInfo(Variant::INT, "count"), "set_count", "get_count"); // int - ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type"); // GLTFDocument::GLTFType + ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type"); // GLTFType ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "min"), "set_min", "get_min"); // Vector<real_t> ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT64_ARRAY, "max"), "set_max", "get_max"); // Vector<real_t> ADD_PROPERTY(PropertyInfo(Variant::INT, "sparse_count"), "set_sparse_count", "get_sparse_count"); // int @@ -123,7 +121,7 @@ int GLTFAccessor::get_type() { } void GLTFAccessor::set_type(int p_type) { - type = (GLTFDocument::GLTFType)p_type; // TODO: Register enum + type = (GLTFType)p_type; // TODO: Register enum } Vector<double> GLTFAccessor::get_min() { diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h index f412dc2c7f..d89cc5d1ae 100644 --- a/modules/gltf/gltf_accessor.h +++ b/modules/gltf/gltf_accessor.h @@ -33,7 +33,7 @@ #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" struct GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); @@ -45,7 +45,7 @@ private: int component_type = 0; bool normalized = false; int count = 0; - GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; + GLTFType type = GLTFType::TYPE_SCALAR; Vector<double> min; Vector<double> max; int sparse_count = 0; diff --git a/modules/gltf/gltf_buffer_view.h b/modules/gltf/gltf_buffer_view.h index 560d56f35c..e28456fd8e 100644 --- a/modules/gltf/gltf_buffer_view.h +++ b/modules/gltf/gltf_buffer_view.h @@ -32,7 +32,7 @@ #define GLTF_BUFFER_VIEW_H #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" class GLTFBufferView : public Resource { GDCLASS(GLTFBufferView, Resource); diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h new file mode 100644 index 0000000000..c20c87f798 --- /dev/null +++ b/modules/gltf/gltf_defines.h @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* gltf_defines.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GLTF_DEFINES_H +#define GLTF_DEFINES_H + +// This file should only be included by other headers. + +// Godot classes used by GLTF headers. +class BoneAttachment3D; +class CSGShape3D; +class DirectionalLight3D; +class GridMap; +class Light3D; +class MultiMeshInstance3D; +class Skeleton3D; +class Skin; + +// GLTF classes. +struct GLTFAccessor; +class GLTFAnimation; +class GLTFBufferView; +class GLTFCamera; +class GLTFDocument; +class GLTFDocumentExtension; +class GLTFLight; +class GLTFMesh; +class GLTFNode; +class GLTFSkeleton; +class GLTFSkin; +class GLTFSpecGloss; +class GLTFState; +class GLTFTexture; + +// GLTF index aliases. +using GLTFAccessorIndex = int; +using GLTFAnimationIndex = int; +using GLTFBufferIndex = int; +using GLTFBufferViewIndex = int; +using GLTFCameraIndex = int; +using GLTFImageIndex = int; +using GLTFMaterialIndex = int; +using GLTFMeshIndex = int; +using GLTFLightIndex = int; +using GLTFNodeIndex = int; +using GLTFSkeletonIndex = int; +using GLTFSkinIndex = int; +using GLTFTextureIndex = int; + +enum GLTFType { + TYPE_SCALAR, + TYPE_VEC2, + TYPE_VEC3, + TYPE_VEC4, + TYPE_MAT2, + TYPE_MAT3, + TYPE_MAT4, +}; + +#endif // GLTF_DEFINES_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index babdc9f33b..aa2ec4a399 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -30,19 +30,10 @@ #include "gltf_document.h" -#include "gltf_accessor.h" -#include "gltf_animation.h" -#include "gltf_camera.h" #include "gltf_document_extension.h" #include "gltf_document_extension_convert_importer_mesh.h" -#include "gltf_light.h" -#include "gltf_mesh.h" -#include "gltf_node.h" -#include "gltf_skeleton.h" -#include "gltf_skin.h" #include "gltf_spec_gloss.h" #include "gltf_state.h" -#include "gltf_texture.h" #include "core/crypto/crypto_core.h" #include "core/error/error_macros.h" @@ -230,15 +221,21 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { } Error GLTFDocument::_serialize_extensions(Ref<GLTFState> state) const { - const String texture_transform = "KHR_texture_transform"; - const String punctual_lights = "KHR_lights_punctual"; Array extensions_used; - extensions_used.push_back(punctual_lights); - extensions_used.push_back(texture_transform); - state->json["extensionsUsed"] = extensions_used; Array extensions_required; - extensions_required.push_back(texture_transform); - state->json["extensionsRequired"] = extensions_required; + if (!state->lights.is_empty()) { + extensions_used.push_back("KHR_lights_punctual"); + } + if (state->use_khr_texture_transform) { + extensions_used.push_back("KHR_texture_transform"); + extensions_required.push_back("KHR_texture_transform"); + } + if (!extensions_used.is_empty()) { + state->json["extensionsUsed"] = extensions_used; + } + if (!extensions_required.is_empty()) { + state->json["extensionsRequired"] = extensions_required; + } return OK; } @@ -934,58 +931,58 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) { return OK; } -String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type) { - if (p_type == GLTFDocument::TYPE_SCALAR) { +String GLTFDocument::_get_accessor_type_name(const GLTFType p_type) { + if (p_type == GLTFType::TYPE_SCALAR) { return "SCALAR"; } - if (p_type == GLTFDocument::TYPE_VEC2) { + if (p_type == GLTFType::TYPE_VEC2) { return "VEC2"; } - if (p_type == GLTFDocument::TYPE_VEC3) { + if (p_type == GLTFType::TYPE_VEC3) { return "VEC3"; } - if (p_type == GLTFDocument::TYPE_VEC4) { + if (p_type == GLTFType::TYPE_VEC4) { return "VEC4"; } - if (p_type == GLTFDocument::TYPE_MAT2) { + if (p_type == GLTFType::TYPE_MAT2) { return "MAT2"; } - if (p_type == GLTFDocument::TYPE_MAT3) { + if (p_type == GLTFType::TYPE_MAT3) { return "MAT3"; } - if (p_type == GLTFDocument::TYPE_MAT4) { + if (p_type == GLTFType::TYPE_MAT4) { return "MAT4"; } ERR_FAIL_V("SCALAR"); } -GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { +GLTFType GLTFDocument::_get_type_from_str(const String &p_string) { if (p_string == "SCALAR") { - return GLTFDocument::TYPE_SCALAR; + return GLTFType::TYPE_SCALAR; } if (p_string == "VEC2") { - return GLTFDocument::TYPE_VEC2; + return GLTFType::TYPE_VEC2; } if (p_string == "VEC3") { - return GLTFDocument::TYPE_VEC3; + return GLTFType::TYPE_VEC3; } if (p_string == "VEC4") { - return GLTFDocument::TYPE_VEC4; + return GLTFType::TYPE_VEC4; } if (p_string == "MAT2") { - return GLTFDocument::TYPE_MAT2; + return GLTFType::TYPE_MAT2; } if (p_string == "MAT3") { - return GLTFDocument::TYPE_MAT3; + return GLTFType::TYPE_MAT3; } if (p_string == "MAT4") { - return GLTFDocument::TYPE_MAT4; + return GLTFType::TYPE_MAT4; } - ERR_FAIL_V(GLTFDocument::TYPE_SCALAR); + ERR_FAIL_V(GLTFType::TYPE_SCALAR); } Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { @@ -1536,7 +1533,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; + const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_INT; accessor->max = type_max; @@ -1620,7 +1617,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC2; + const GLTFType type = GLTFType::TYPE_VEC2; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1669,7 +1666,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1734,7 +1731,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1781,7 +1778,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_UNSIGNED_SHORT; accessor->max = type_max; @@ -1830,7 +1827,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> s accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; + const GLTFType type = GLTFType::TYPE_VEC4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1895,7 +1892,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; + const GLTFType type = GLTFType::TYPE_SCALAR; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -1941,7 +1938,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC3; + const GLTFType type = GLTFType::TYPE_VEC3; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -2009,7 +2006,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); - const GLTFDocument::GLTFType type = GLTFDocument::TYPE_MAT4; + const GLTFType type = GLTFType::TYPE_MAT4; const int component_type = GLTFDocument::COMPONENT_TYPE_FLOAT; accessor->max = type_max; @@ -3305,7 +3302,11 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } if (gltf_texture_index != -1) { bct["index"] = gltf_texture_index; - bct["extensions"] = _serialize_texture_transform_uv1(material); + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + state->use_khr_texture_transform = true; + } mr["baseColorTexture"] = bct; } } @@ -3436,7 +3437,11 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } if (has_roughness || has_metalness) { mrt["index"] = orm_texture_index; - mrt["extensions"] = _serialize_texture_transform_uv1(material); + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + state->use_khr_texture_transform = true; + } mr["metallicRoughnessTexture"] = mrt; } } @@ -4525,6 +4530,9 @@ void GLTFDocument::_remove_duplicate_skins(Ref<GLTFState> state) { } Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) { + if (state->lights.is_empty()) { + return OK; + } Array lights; for (GLTFLightIndex i = 0; i < state->lights.size(); i++) { Dictionary d; @@ -4551,10 +4559,6 @@ Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) { lights.push_back(d); } - if (!state->lights.size()) { - return OK; - } - Dictionary extensions; if (state->json.has("extensions")) { extensions = state->json["extensions"]; @@ -6651,45 +6655,48 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> return OK; } -Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { - Dictionary extension; - Ref<BaseMaterial3D> mat = p_material; - if (mat.is_valid()) { - Dictionary texture_transform; +Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) { + Dictionary texture_transform; + bool is_offset = p_offset != Vector2(0.0, 0.0); + if (is_offset) { Array offset; offset.resize(2); - offset[0] = mat->get_uv2_offset().x; - offset[1] = mat->get_uv2_offset().y; + offset[0] = p_offset.x; + offset[1] = p_offset.y; texture_transform["offset"] = offset; + } + bool is_scaled = p_scale != Vector2(1.0, 1.0); + if (is_scaled) { Array scale; scale.resize(2); - scale[0] = mat->get_uv2_scale().x; - scale[1] = mat->get_uv2_scale().y; + scale[0] = p_scale.x; + scale[1] = p_scale.y; texture_transform["scale"] = scale; - // Godot doesn't support texture rotation + } + Dictionary extension; + // Note: Godot doesn't support texture rotation. + if (is_offset || is_scaled) { extension["KHR_texture_transform"] = texture_transform; } return extension; } Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { - Dictionary extension; if (p_material.is_valid()) { - Dictionary texture_transform; - Array offset; - offset.resize(2); - offset[0] = p_material->get_uv1_offset().x; - offset[1] = p_material->get_uv1_offset().y; - texture_transform["offset"] = offset; - Array scale; - scale.resize(2); - scale[0] = p_material->get_uv1_scale().x; - scale[1] = p_material->get_uv1_scale().y; - texture_transform["scale"] = scale; - // Godot doesn't support texture rotation - extension["KHR_texture_transform"] = texture_transform; + Vector3 offset = p_material->get_uv1_offset(); + Vector3 scale = p_material->get_uv1_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); } - return extension; + return Dictionary(); +} + +Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { + if (p_material.is_valid()) { + Vector3 offset = p_material->get_uv2_offset(); + Vector3 scale = p_material->get_uv2_scale(); + return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); + } + return Dictionary(); } Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { @@ -6929,15 +6936,6 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; - _convert_scene_node(state, p_node, -1, -1); - if (!state->buffers.size()) { - state->buffers.push_back(Vector<uint8_t>()); - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { - Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; - ERR_CONTINUE(ext.is_null()); - } - for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; ERR_CONTINUE(ext.is_null()); @@ -6948,7 +6946,6 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); } - return OK; } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 2f61210ff9..0c585bf49b 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -32,47 +32,18 @@ #define GLTF_DOCUMENT_H #include "gltf_animation.h" +#include "gltf_defines.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/material.h" #include "modules/modules_enabled.gen.h" // For csg, gridmap. -#include <cstdint> - -class GLTFState; -class GLTFSkin; -class GLTFNode; -class GLTFSpecGloss; -class GLTFSkeleton; -class CSGShape3D; -class GridMap; -class MultiMeshInstance3D; -class GLTFDocumentExtension; - -using GLTFAccessorIndex = int; -using GLTFAnimationIndex = int; -using GLTFBufferIndex = int; -using GLTFBufferViewIndex = int; -using GLTFCameraIndex = int; -using GLTFImageIndex = int; -using GLTFMaterialIndex = int; -using GLTFMeshIndex = int; -using GLTFLightIndex = int; -using GLTFNodeIndex = int; -using GLTFSkeletonIndex = int; -using GLTFSkinIndex = int; -using GLTFTextureIndex = int; - class GLTFDocument : public Resource { GDCLASS(GLTFDocument, Resource); - friend class GLTFState; - friend class GLTFSkin; - friend class GLTFSkeleton; TypedArray<GLTFDocumentExtension> document_extensions; private: @@ -81,15 +52,6 @@ private: public: GLTFDocument(); const int32_t JOINT_GROUP_SIZE = 4; - enum GLTFType { - TYPE_SCALAR, - TYPE_VEC2, - TYPE_VEC3, - TYPE_VEC4, - TYPE_MAT2, - TYPE_MAT3, - TYPE_MAT4, - }; enum { ARRAY_BUFFER = 34962, @@ -118,58 +80,6 @@ public: TypedArray<GLTFDocumentExtension> get_extensions() const; private: - template <class T> - static Array to_array(const Vector<T> &p_inp) { - Array ret; - for (int i = 0; i < p_inp.size(); i++) { - ret.push_back(p_inp[i]); - } - return ret; - } - - template <class T> - static Array to_array(const HashSet<T> &p_inp) { - Array ret; - typename HashSet<T>::Iterator elem = p_inp.begin(); - while (elem) { - ret.push_back(*elem); - ++elem; - } - return ret; - } - - template <class T> - static void set_from_array(Vector<T> &r_out, const Array &p_inp) { - r_out.clear(); - for (int i = 0; i < p_inp.size(); i++) { - r_out.push_back(p_inp[i]); - } - } - - template <class T> - static void set_from_array(HashSet<T> &r_out, const Array &p_inp) { - r_out.clear(); - for (int i = 0; i < p_inp.size(); i++) { - r_out.insert(p_inp[i]); - } - } - template <class K, class V> - static Dictionary to_dict(const HashMap<K, V> &p_inp) { - Dictionary ret; - for (const KeyValue<K, V> &E : p_inp) { - ret[E.key] = E.value; - } - return ret; - } - - template <class K, class V> - static void set_from_dict(HashMap<K, V> &r_out, const Dictionary &p_inp) { - r_out.clear(); - Array keys = p_inp.keys(); - for (int i = 0; i < keys.size(); i++) { - r_out[keys[i]] = p_inp[keys[i]]; - } - } void _build_parent_hierachy(Ref<GLTFState> state); double _filter_number(double p_float); String _get_component_type_name(const uint32_t p_component); @@ -177,7 +87,7 @@ private: Error _parse_scenes(Ref<GLTFState> state); Error _parse_nodes(Ref<GLTFState> state); String _get_type_name(const GLTFType p_component); - String _get_accessor_type_name(const GLTFDocument::GLTFType p_type); + String _get_accessor_type_name(const GLTFType p_type); String _gen_unique_name(Ref<GLTFState> state, const String &p_name); String _sanitize_animation_name(const String &name); String _gen_unique_animation_name(Ref<GLTFState> state, const String &p_name); diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h index 556f79e887..8fd4d4e54e 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/gltf_document_extension.h @@ -31,7 +31,6 @@ #ifndef GLTF_DOCUMENT_EXTENSION_H #define GLTF_DOCUMENT_EXTENSION_H -#include "gltf_accessor.h" #include "gltf_node.h" #include "gltf_state.h" diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.h index 4c9e42a00f..b7798c9517 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h @@ -37,8 +37,6 @@ #include "scene/3d/mesh_instance_3d.h" #include "scene/resources/importer_mesh.h" -class GLTFDocumentExtension; -class GLTFDocument; class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension { GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension); diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h index 25e0835a33..58fa299dfd 100644 --- a/modules/gltf/gltf_light.h +++ b/modules/gltf/gltf_light.h @@ -33,6 +33,7 @@ #include "core/config/engine.h" #include "core/io/resource.h" +#include "scene/3d/light_3d.h" class GLTFLight : public Resource { GDCLASS(GLTFLight, Resource) diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h index 929ad3eca0..7b03b55fbc 100644 --- a/modules/gltf/gltf_node.h +++ b/modules/gltf/gltf_node.h @@ -32,7 +32,7 @@ #define GLTF_NODE_H #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" class GLTFNode : public Resource { GDCLASS(GLTFNode, Resource); diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp index b813f39a27..994e9bf6e7 100644 --- a/modules/gltf/gltf_skeleton.cpp +++ b/modules/gltf/gltf_skeleton.cpp @@ -30,6 +30,9 @@ #include "gltf_skeleton.h" +#include "gltf_template_convert.h" +#include "scene/3d/bone_attachment_3d.h" + void GLTFSkeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joints"), &GLTFSkeleton::get_joints); ClassDB::bind_method(D_METHOD("set_joints", "joints"), &GLTFSkeleton::set_joints); @@ -70,19 +73,19 @@ Skeleton3D *GLTFSkeleton::get_godot_skeleton() { } Array GLTFSkeleton::get_unique_names() { - return GLTFDocument::to_array(unique_names); + return GLTFTemplateConvert::to_array(unique_names); } void GLTFSkeleton::set_unique_names(Array p_unique_names) { - GLTFDocument::set_from_array(unique_names, p_unique_names); + GLTFTemplateConvert::set_from_array(unique_names, p_unique_names); } Dictionary GLTFSkeleton::get_godot_bone_node() { - return GLTFDocument::to_dict(godot_bone_node); + return GLTFTemplateConvert::to_dict(godot_bone_node); } void GLTFSkeleton::set_godot_bone_node(Dictionary p_indict) { - GLTFDocument::set_from_dict(godot_bone_node, p_indict); + GLTFTemplateConvert::set_from_dict(godot_bone_node, p_indict); } BoneAttachment3D *GLTFSkeleton::get_bone_attachment(int idx) { diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h index 92ee6e6234..eaeff0c0cb 100644 --- a/modules/gltf/gltf_skeleton.h +++ b/modules/gltf/gltf_skeleton.h @@ -32,7 +32,7 @@ #define GLTF_SKELETON_H #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" class GLTFSkeleton : public Resource { GDCLASS(GLTFSkeleton, Resource); diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp index e8005aa0c1..8b0ca7546c 100644 --- a/modules/gltf/gltf_skin.cpp +++ b/modules/gltf/gltf_skin.cpp @@ -30,6 +30,9 @@ #include "gltf_skin.h" +#include "gltf_template_convert.h" +#include "scene/resources/skin.h" + void GLTFSkin::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skin_root"), &GLTFSkin::get_skin_root); ClassDB::bind_method(D_METHOD("set_skin_root", "skin_root"), &GLTFSkin::set_skin_root); @@ -81,11 +84,11 @@ void GLTFSkin::set_joints_original(Vector<GLTFNodeIndex> p_joints_original) { } Array GLTFSkin::get_inverse_binds() { - return GLTFDocument::to_array(inverse_binds); + return GLTFTemplateConvert::to_array(inverse_binds); } void GLTFSkin::set_inverse_binds(Array p_inverse_binds) { - GLTFDocument::set_from_array(inverse_binds, p_inverse_binds); + GLTFTemplateConvert::set_from_array(inverse_binds, p_inverse_binds); } Vector<GLTFNodeIndex> GLTFSkin::get_joints() { @@ -121,11 +124,11 @@ void GLTFSkin::set_skeleton(int p_skeleton) { } Dictionary GLTFSkin::get_joint_i_to_bone_i() { - return GLTFDocument::to_dict(joint_i_to_bone_i); + return GLTFTemplateConvert::to_dict(joint_i_to_bone_i); } void GLTFSkin::set_joint_i_to_bone_i(Dictionary p_joint_i_to_bone_i) { - GLTFDocument::set_from_dict(joint_i_to_bone_i, p_joint_i_to_bone_i); + GLTFTemplateConvert::set_from_dict(joint_i_to_bone_i, p_joint_i_to_bone_i); } Dictionary GLTFSkin::get_joint_i_to_name() { diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h index d946324756..a3f0b2c8af 100644 --- a/modules/gltf/gltf_skin.h +++ b/modules/gltf/gltf_skin.h @@ -32,7 +32,7 @@ #define GLTF_SKIN_H #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" class GLTFSkin : public Resource { GDCLASS(GLTFSkin, Resource); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 989fa476c2..a5f7bcf9d6 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -150,51 +150,51 @@ void GLTFState::set_use_named_skin_binds(bool p_use_named_skin_binds) { } Array GLTFState::get_nodes() { - return GLTFDocument::to_array(nodes); + return GLTFTemplateConvert::to_array(nodes); } void GLTFState::set_nodes(Array p_nodes) { - GLTFDocument::set_from_array(nodes, p_nodes); + GLTFTemplateConvert::set_from_array(nodes, p_nodes); } Array GLTFState::get_buffers() { - return GLTFDocument::to_array(buffers); + return GLTFTemplateConvert::to_array(buffers); } void GLTFState::set_buffers(Array p_buffers) { - GLTFDocument::set_from_array(buffers, p_buffers); + GLTFTemplateConvert::set_from_array(buffers, p_buffers); } Array GLTFState::get_buffer_views() { - return GLTFDocument::to_array(buffer_views); + return GLTFTemplateConvert::to_array(buffer_views); } void GLTFState::set_buffer_views(Array p_buffer_views) { - GLTFDocument::set_from_array(buffer_views, p_buffer_views); + GLTFTemplateConvert::set_from_array(buffer_views, p_buffer_views); } Array GLTFState::get_accessors() { - return GLTFDocument::to_array(accessors); + return GLTFTemplateConvert::to_array(accessors); } void GLTFState::set_accessors(Array p_accessors) { - GLTFDocument::set_from_array(accessors, p_accessors); + GLTFTemplateConvert::set_from_array(accessors, p_accessors); } Array GLTFState::get_meshes() { - return GLTFDocument::to_array(meshes); + return GLTFTemplateConvert::to_array(meshes); } void GLTFState::set_meshes(Array p_meshes) { - GLTFDocument::set_from_array(meshes, p_meshes); + GLTFTemplateConvert::set_from_array(meshes, p_meshes); } Array GLTFState::get_materials() { - return GLTFDocument::to_array(materials); + return GLTFTemplateConvert::to_array(materials); } void GLTFState::set_materials(Array p_materials) { - GLTFDocument::set_from_array(materials, p_materials); + GLTFTemplateConvert::set_from_array(materials, p_materials); } String GLTFState::get_scene_name() { @@ -206,91 +206,91 @@ void GLTFState::set_scene_name(String p_scene_name) { } Array GLTFState::get_root_nodes() { - return GLTFDocument::to_array(root_nodes); + return GLTFTemplateConvert::to_array(root_nodes); } void GLTFState::set_root_nodes(Array p_root_nodes) { - GLTFDocument::set_from_array(root_nodes, p_root_nodes); + GLTFTemplateConvert::set_from_array(root_nodes, p_root_nodes); } Array GLTFState::get_textures() { - return GLTFDocument::to_array(textures); + return GLTFTemplateConvert::to_array(textures); } void GLTFState::set_textures(Array p_textures) { - GLTFDocument::set_from_array(textures, p_textures); + GLTFTemplateConvert::set_from_array(textures, p_textures); } Array GLTFState::get_images() { - return GLTFDocument::to_array(images); + return GLTFTemplateConvert::to_array(images); } void GLTFState::set_images(Array p_images) { - GLTFDocument::set_from_array(images, p_images); + GLTFTemplateConvert::set_from_array(images, p_images); } Array GLTFState::get_skins() { - return GLTFDocument::to_array(skins); + return GLTFTemplateConvert::to_array(skins); } void GLTFState::set_skins(Array p_skins) { - GLTFDocument::set_from_array(skins, p_skins); + GLTFTemplateConvert::set_from_array(skins, p_skins); } Array GLTFState::get_cameras() { - return GLTFDocument::to_array(cameras); + return GLTFTemplateConvert::to_array(cameras); } void GLTFState::set_cameras(Array p_cameras) { - GLTFDocument::set_from_array(cameras, p_cameras); + GLTFTemplateConvert::set_from_array(cameras, p_cameras); } Array GLTFState::get_lights() { - return GLTFDocument::to_array(lights); + return GLTFTemplateConvert::to_array(lights); } void GLTFState::set_lights(Array p_lights) { - GLTFDocument::set_from_array(lights, p_lights); + GLTFTemplateConvert::set_from_array(lights, p_lights); } Array GLTFState::get_unique_names() { - return GLTFDocument::to_array(unique_names); + return GLTFTemplateConvert::to_array(unique_names); } void GLTFState::set_unique_names(Array p_unique_names) { - GLTFDocument::set_from_array(unique_names, p_unique_names); + GLTFTemplateConvert::set_from_array(unique_names, p_unique_names); } Array GLTFState::get_unique_animation_names() { - return GLTFDocument::to_array(unique_animation_names); + return GLTFTemplateConvert::to_array(unique_animation_names); } void GLTFState::set_unique_animation_names(Array p_unique_animation_names) { - GLTFDocument::set_from_array(unique_animation_names, p_unique_animation_names); + GLTFTemplateConvert::set_from_array(unique_animation_names, p_unique_animation_names); } Array GLTFState::get_skeletons() { - return GLTFDocument::to_array(skeletons); + return GLTFTemplateConvert::to_array(skeletons); } void GLTFState::set_skeletons(Array p_skeletons) { - GLTFDocument::set_from_array(skeletons, p_skeletons); + GLTFTemplateConvert::set_from_array(skeletons, p_skeletons); } Dictionary GLTFState::get_skeleton_to_node() { - return GLTFDocument::to_dict(skeleton_to_node); + return GLTFTemplateConvert::to_dict(skeleton_to_node); } void GLTFState::set_skeleton_to_node(Dictionary p_skeleton_to_node) { - GLTFDocument::set_from_dict(skeleton_to_node, p_skeleton_to_node); + GLTFTemplateConvert::set_from_dict(skeleton_to_node, p_skeleton_to_node); } Array GLTFState::get_animations() { - return GLTFDocument::to_array(animations); + return GLTFTemplateConvert::to_array(animations); } void GLTFState::set_animations(Array p_animations) { - GLTFDocument::set_from_array(animations, p_animations); + GLTFTemplateConvert::set_from_array(animations, p_animations); } Node *GLTFState::get_scene_node(GLTFNodeIndex idx) { diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 2fdef19038..dd6a65e496 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -35,13 +35,12 @@ #include "gltf_animation.h" #include "gltf_buffer_view.h" #include "gltf_camera.h" -#include "gltf_document.h" -#include "gltf_document_extension.h" #include "gltf_light.h" #include "gltf_mesh.h" #include "gltf_node.h" #include "gltf_skeleton.h" #include "gltf_skin.h" +#include "gltf_template_convert.h" #include "gltf_texture.h" #include "core/templates/rb_map.h" @@ -60,6 +59,7 @@ class GLTFState : public Resource { Vector<uint8_t> glb_data; bool use_named_skin_binds = false; + bool use_khr_texture_transform = false; bool discard_meshes_and_materials = false; Vector<Ref<GLTFNode>> nodes; diff --git a/modules/gltf/gltf_template_convert.h b/modules/gltf/gltf_template_convert.h new file mode 100644 index 0000000000..c915d3deb0 --- /dev/null +++ b/modules/gltf/gltf_template_convert.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* gltf_template_convert.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GLTF_TEMPLATE_CONVERT_H +#define GLTF_TEMPLATE_CONVERT_H + +#include "core/templates/hash_set.h" +#include "core/variant/array.h" +#include "core/variant/dictionary.h" + +namespace GLTFTemplateConvert { +template <class T> +static Array to_array(const Vector<T> &p_inp) { + Array ret; + for (int i = 0; i < p_inp.size(); i++) { + ret.push_back(p_inp[i]); + } + return ret; +} + +template <class T> +static Array to_array(const HashSet<T> &p_inp) { + Array ret; + typename HashSet<T>::Iterator elem = p_inp.begin(); + while (elem) { + ret.push_back(*elem); + ++elem; + } + return ret; +} + +template <class T> +static void set_from_array(Vector<T> &r_out, const Array &p_inp) { + r_out.clear(); + for (int i = 0; i < p_inp.size(); i++) { + r_out.push_back(p_inp[i]); + } +} + +template <class T> +static void set_from_array(HashSet<T> &r_out, const Array &p_inp) { + r_out.clear(); + for (int i = 0; i < p_inp.size(); i++) { + r_out.insert(p_inp[i]); + } +} + +template <class K, class V> +static Dictionary to_dict(const HashMap<K, V> &p_inp) { + Dictionary ret; + for (const KeyValue<K, V> &E : p_inp) { + ret[E.key] = E.value; + } + return ret; +} + +template <class K, class V> +static void set_from_dict(HashMap<K, V> &r_out, const Dictionary &p_inp) { + r_out.clear(); + Array keys = p_inp.keys(); + for (int i = 0; i < keys.size(); i++) { + r_out[keys[i]] = p_inp[keys[i]]; + } +} +} //namespace GLTFTemplateConvert + +#endif // GLTF_TEMPLATE_CONVERT_H diff --git a/modules/gltf/gltf_texture.h b/modules/gltf/gltf_texture.h index 54dd61f9a5..2c1c5c2275 100644 --- a/modules/gltf/gltf_texture.h +++ b/modules/gltf/gltf_texture.h @@ -32,7 +32,7 @@ #define GLTF_TEXTURE_H #include "core/io/resource.h" -#include "gltf_document.h" +#include "gltf_defines.h" class GLTFTexture : public Resource { GDCLASS(GLTFTexture, Resource); diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index c37bea519f..98bcdea8f4 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -46,6 +46,12 @@ int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { int frames_mixed_this_step = p_frames; + int beat_length_frames = -1; + bool beat_loop = mp3_stream->has_loop() && mp3_stream->get_bpm() > 0 && mp3_stream->get_beat_count() > 0; + if (beat_loop) { + beat_length_frames = mp3_stream->get_beat_count() * mp3_stream->sample_rate * 60 / mp3_stream->get_bpm(); + } + while (todo && active) { mp3dec_frame_info_t frame_info; mp3d_sample_t *buf_frame = nullptr; @@ -54,8 +60,25 @@ int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { if (samples_mixed) { p_buffer[p_frames - todo] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]); + if (loop_fade_remaining < FADE_SIZE) { + p_buffer[p_frames - todo] += loop_fade[loop_fade_remaining] * (float(FADE_SIZE - loop_fade_remaining) / float(FADE_SIZE)); + loop_fade_remaining++; + } --todo; ++frames_mixed; + + if (beat_loop && (int)frames_mixed >= beat_length_frames) { + for (int i = 0; i < FADE_SIZE; i++) { + samples_mixed = mp3dec_ex_read_frame(mp3d, &buf_frame, &frame_info, mp3_stream->channels); + loop_fade[i] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]); + if (!samples_mixed) { + break; + } + } + loop_fade_remaining = 0; + seek(mp3_stream->loop_offset); + loops++; + } } else { @@ -117,6 +140,10 @@ void AudioStreamPlaybackMP3::seek(float p_time) { mp3dec_ex_seek(mp3d, (uint64_t)frames_mixed * mp3_stream->channels); } +void AudioStreamPlaybackMP3::tag_used_streams() { + mp3_stream->tag_used(get_playback_position()); +} + AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { if (mp3d) { mp3dec_ex_close(mp3d); @@ -124,7 +151,7 @@ AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { } } -Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() { +Ref<AudioStreamPlayback> AudioStreamMP3::instantiate_playback() { Ref<AudioStreamPlaybackMP3> mp3s; ERR_FAIL_COND_V_MSG(data.is_empty(), mp3s, @@ -206,6 +233,36 @@ bool AudioStreamMP3::is_monophonic() const { return false; } +void AudioStreamMP3::set_bpm(double p_bpm) { + ERR_FAIL_COND(p_bpm < 0); + bpm = p_bpm; + emit_changed(); +} + +double AudioStreamMP3::get_bpm() const { + return bpm; +} + +void AudioStreamMP3::set_beat_count(int p_beat_count) { + ERR_FAIL_COND(p_beat_count < 0); + beat_count = p_beat_count; + emit_changed(); +} + +int AudioStreamMP3::get_beat_count() const { + return beat_count; +} + +void AudioStreamMP3::set_bar_beats(int p_bar_beats) { + ERR_FAIL_COND(p_bar_beats < 0); + bar_beats = p_bar_beats; + emit_changed(); +} + +int AudioStreamMP3::get_bar_beats() const { + return bar_beats; +} + void AudioStreamMP3::_bind_methods() { ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamMP3::set_data); ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamMP3::get_data); @@ -216,7 +273,19 @@ void AudioStreamMP3::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamMP3::set_loop_offset); ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamMP3::get_loop_offset); + ClassDB::bind_method(D_METHOD("set_bpm", "bpm"), &AudioStreamMP3::set_bpm); + ClassDB::bind_method(D_METHOD("get_bpm"), &AudioStreamMP3::get_bpm); + + ClassDB::bind_method(D_METHOD("set_beat_count", "count"), &AudioStreamMP3::set_beat_count); + ClassDB::bind_method(D_METHOD("get_beat_count"), &AudioStreamMP3::get_beat_count); + + ClassDB::bind_method(D_METHOD("set_bar_beats", "count"), &AudioStreamMP3::set_bar_beats); + ClassDB::bind_method(D_METHOD("get_bar_beats"), &AudioStreamMP3::get_bar_beats); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), "set_bpm", "get_bpm"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,1,or_greater"), "set_beat_count", "get_beat_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,1,or_greater"), "set_bar_beats", "get_bar_beats"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset"); } diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h index c1a60ddccb..428ac1240e 100644 --- a/modules/minimp3/audio_stream_mp3.h +++ b/modules/minimp3/audio_stream_mp3.h @@ -41,6 +41,12 @@ class AudioStreamMP3; class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled { GDCLASS(AudioStreamPlaybackMP3, AudioStreamPlaybackResampled); + enum { + FADE_SIZE = 256 + }; + AudioFrame loop_fade[FADE_SIZE]; + int loop_fade_remaining = FADE_SIZE; + mp3dec_ex_t *mp3d = nullptr; uint32_t frames_mixed = 0; bool active = false; @@ -64,6 +70,8 @@ public: virtual float get_playback_position() const override; virtual void seek(float p_time) override; + virtual void tag_used_streams() override; + AudioStreamPlaybackMP3() {} ~AudioStreamPlaybackMP3(); }; @@ -85,17 +93,30 @@ class AudioStreamMP3 : public AudioStream { float loop_offset = 0.0; void clear_data(); + double bpm = 0; + int beat_count = 0; + int bar_beats = 4; + protected: static void _bind_methods(); public: void set_loop(bool p_enable); - bool has_loop() const; + virtual bool has_loop() const override; void set_loop_offset(float p_seconds); float get_loop_offset() const; - virtual Ref<AudioStreamPlayback> instance_playback() override; + void set_bpm(double p_bpm); + virtual double get_bpm() const override; + + void set_beat_count(int p_beat_count); + virtual int get_beat_count() const override; + + void set_bar_beats(int p_bar_beats); + virtual int get_bar_beats() const override; + + virtual Ref<AudioStreamPlayback> instantiate_playback() override; virtual String get_stream_name() const override; void set_data(const Vector<uint8_t> &p_data); diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml index 404f6c31e5..8f03681c06 100644 --- a/modules/minimp3/doc_classes/AudioStreamMP3.xml +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -9,6 +9,12 @@ <tutorials> </tutorials> <members> + <member name="bar_beats" type="int" setter="set_bar_beats" getter="get_bar_beats" default="4"> + </member> + <member name="beat_count" type="int" setter="set_beat_count" getter="get_beat_count" default="0"> + </member> + <member name="bpm" type="float" setter="set_bpm" getter="get_bpm" default="0.0"> + </member> <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. You can load a file without having to import it beforehand using the code snippet below. Keep in mind that this snippet loads the whole file into memory and may not be ideal for huge files (hundreds of megabytes or more). diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index e03940f963..8526aeef38 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -34,6 +34,10 @@ #include "core/io/resource_saver.h" #include "scene/resources/texture.h" +#ifdef TOOLS_ENABLED +#include "editor/import/audio_stream_import_settings.h" +#endif + String ResourceImporterMP3::get_importer_name() const { return "mp3"; } @@ -69,14 +73,26 @@ String ResourceImporterMP3::get_preset_name(int p_idx) const { void ResourceImporterMP3::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,or_greater"), 4)); } -Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - bool loop = p_options["loop"]; - float loop_offset = p_options["loop_offset"]; +#ifdef TOOLS_ENABLED +bool ResourceImporterMP3::has_advanced_options() const { + return true; +} +void ResourceImporterMP3::show_advanced_options(const String &p_path) { + Ref<AudioStreamMP3> mp3_stream = import_mp3(p_path); + if (mp3_stream.is_valid()) { + AudioStreamImportSettings::get_singleton()->edit(p_path, "mp3", mp3_stream); + } +} +#endif - Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); - ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN); +Ref<AudioStreamMP3> ResourceImporterMP3::import_mp3(const String &p_path) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V(f.is_null(), Ref<AudioStreamMP3>()); uint64_t len = f->get_length(); @@ -90,9 +106,27 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s mp3_stream.instantiate(); mp3_stream->set_data(data); - ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(!mp3_stream->get_data().size(), Ref<AudioStreamMP3>()); + + return mp3_stream; +} + +Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + bool loop = p_options["loop"]; + float loop_offset = p_options["loop_offset"]; + double bpm = p_options["bpm"]; + float beat_count = p_options["beat_count"]; + float bar_beats = p_options["bar_beats"]; + + Ref<AudioStreamMP3> mp3_stream = import_mp3(p_source_file); + if (mp3_stream.is_null()) { + return ERR_CANT_OPEN; + } mp3_stream->set_loop(loop); mp3_stream->set_loop_offset(loop_offset); + mp3_stream->set_bpm(bpm); + mp3_stream->set_beat_count(beat_count); + mp3_stream->set_bar_beats(bar_beats); return ResourceSaver::save(p_save_path + ".mp3str", mp3_stream); } diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h index 678a3773bb..38729d68f8 100644 --- a/modules/minimp3/resource_importer_mp3.h +++ b/modules/minimp3/resource_importer_mp3.h @@ -50,6 +50,12 @@ public: virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override; virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; +#ifdef TOOLS_ENABLED + virtual bool has_advanced_options() const override; + virtual void show_advanced_options(const String &p_path) override; +#endif + static Ref<AudioStreamMP3> import_mp3(const String &p_path); + virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; ResourceImporterMP3(); diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 5876b6cbf3..95f1a657a4 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -45,7 +45,7 @@ uint32_t MobileVRInterface::get_capabilities() const { Vector3 MobileVRInterface::scale_magneto(const Vector3 &p_magnetometer) { // Our magnetometer doesn't give us nice clean data. - // Well it may on Mac OS X because we're getting a calibrated value in the current implementation but Android we're getting raw data. + // Well it may on macOS because we're getting a calibrated value in the current implementation but Android we're getting raw data. // This is a fairly simple adjustment we can do to correct for the magnetometer data being elliptical Vector3 mag_raw = p_magnetometer; diff --git a/modules/mono/SCsub b/modules/mono/SCsub index 3bafa351a9..d10ebc7b47 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -55,7 +55,7 @@ env_mono.add_source_files(env.modules_sources, "utils/*.cpp") env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.cpp") -if env["platform"] in ["osx", "iphone"]: +if env["platform"] in ["macos", "ios"]: env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.mm") env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.m") elif env["platform"] == "android": diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 8e441e7e07..e69904c54b 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -63,15 +63,15 @@ def copy_file(src_dir, dst_dir, src_name, dst_name=""): def is_desktop(platform): - return platform in ["windows", "osx", "linuxbsd", "server", "uwp", "haiku"] + return platform in ["windows", "macos", "linuxbsd", "server", "uwp", "haiku"] def is_unix_like(platform): - return platform in ["osx", "linuxbsd", "server", "android", "haiku", "iphone"] + return platform in ["macos", "linuxbsd", "server", "android", "haiku", "ios"] def module_supports_tools_on(platform): - return platform not in ["android", "javascript", "iphone"] + return platform not in ["android", "javascript", "ios"] def find_wasm_src_dir(mono_root): @@ -89,7 +89,7 @@ def configure(env, env_mono): bits = env["bits"] is_android = env["platform"] == "android" is_javascript = env["platform"] == "javascript" - is_ios = env["platform"] == "iphone" + is_ios = env["platform"] == "ios" is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] tools_enabled = env["tools"] @@ -206,7 +206,7 @@ def configure(env, env_mono): copy_file(mono_bin_path, "#bin", mono_dll_file) else: - is_apple = env["platform"] in ["osx", "iphone"] + is_apple = env["platform"] in ["macos", "ios"] is_macos = is_apple and not is_ios sharedlib_ext = ".dylib" if is_apple else ".so" @@ -221,7 +221,7 @@ def configure(env, env_mono): ) if not mono_root and is_macos: - # Try with some known directories under OSX + # Try with some known directories under macOS hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"] for hint_dir in hint_dirs: if os.path.isdir(hint_dir): @@ -270,7 +270,7 @@ def configure(env, env_mono): def copy_mono_lib(libname_wo_ext): copy_file( - mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.iphone.%s.a" % (libname_wo_ext, arch) + mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.ios.%s.a" % (libname_wo_ext, arch) ) # Copy Mono libraries to the output folder. These are meant to be bundled with @@ -539,7 +539,7 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): os.makedirs(target_mono_lib_dir) lib_file_names = [] - if platform == "osx": + if platform == "macos": lib_file_names = [ lib_name + ".dylib" for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"] diff --git a/modules/mono/config.py b/modules/mono/config.py index df02d9a309..3e6584590c 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -1,4 +1,4 @@ -supported_platforms = ["windows", "osx", "linuxbsd", "server", "android", "haiku", "javascript", "iphone"] +supported_platforms = ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"] def can_build(env, platform): @@ -15,7 +15,7 @@ def configure(env): from SCons.Script import BoolVariable, PathVariable, Variables, Help - default_mono_static = platform in ["iphone", "javascript"] + default_mono_static = platform in ["ios", "javascript"] default_mono_bundles_zlib = platform in ["javascript"] envvars = Variables() diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props index 0128f5c706..5a499742e9 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props @@ -57,7 +57,7 @@ <PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' "> <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform> <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(FreeBSD))' ">linuxbsd</GodotTargetPlatform> - <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">osx</GodotTargetPlatform> + <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">macos</GodotTargetPlatform> <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Windows))' ">windows</GodotTargetPlatform> </PropertyGroup> @@ -76,12 +76,12 @@ --> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants> - <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'osx' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'server' ">GODOT_SERVER;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants> - <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'iphone' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants> + <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'javascript' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants> <GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants)</GodotDefineConstants> diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index e2f4d2f5fd..e9718cc82c 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -336,10 +336,10 @@ MONO_AOT_MODE_LAST = 1000, // Add the required Mono libraries to the Xcode project - string MonoLibFile(string libFileName) => libFileName + ".iphone.fat.a"; + string MonoLibFile(string libFileName) => libFileName + ".ios.fat.a"; string MonoLibFromTemplate(string libFileName) => - Path.Combine(Internal.FullTemplatesDir, "iphone-mono-libs", MonoLibFile(libFileName)); + Path.Combine(Internal.FullExportTemplatesDir, "ios-mono-libs", MonoLibFile(libFileName)); exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmonosgen-2.0")); diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 3e46a89b7c..cca18a2a1f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -337,7 +337,7 @@ namespace GodotTools.Export string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}"; - string templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName()); + string templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName()); bool validTemplatePathFound = true; if (!Directory.Exists(templateDirPath)) @@ -347,7 +347,7 @@ namespace GodotTools.Export if (isDebug) { target = "debug"; // Support both 'release_debug' and 'debug' for the template data directory name - templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName()); + templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName()); validTemplatePathFound = true; if (!Directory.Exists(templateDirPath)) @@ -380,7 +380,7 @@ namespace GodotTools.Export private static bool PlatformHasTemplateDir(string platform) { - // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest. + // macOS export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest. return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform); } @@ -398,13 +398,13 @@ namespace GodotTools.Export private static string GetBclProfileDir(string profile) { - string templatesDir = Internal.FullTemplatesDir; + string templatesDir = Internal.FullExportTemplatesDir; return Path.Combine(templatesDir, "bcl", profile); } private static string DeterminePlatformBclDir(string platform) { - string templatesDir = Internal.FullTemplatesDir; + string templatesDir = Internal.FullExportTemplatesDir; string platformBclDir = Path.Combine(templatesDir, "bcl", platform); if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll"))) diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 69960bdbeb..b39c3d1c0d 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -263,16 +263,16 @@ namespace GodotTools var args = new List<string>(); - bool osxAppBundleInstalled = false; + bool macOSAppBundleInstalled = false; if (OS.IsMacOS) { // The package path is '/Applications/Visual Studio Code.app' const string vscodeBundleId = "com.microsoft.VSCode"; - osxAppBundleInstalled = Internal.IsOsxAppBundleInstalled(vscodeBundleId); + macOSAppBundleInstalled = Internal.IsMacOSAppBundleInstalled(vscodeBundleId); - if (osxAppBundleInstalled) + if (macOSAppBundleInstalled) { args.Add("-b"); args.Add(vscodeBundleId); @@ -307,13 +307,13 @@ namespace GodotTools if (OS.IsMacOS) { - if (!osxAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath)) + if (!macOSAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath)) { GD.PushError("Cannot find code editor: VSCode"); return Error.FileNotFound; } - command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath; + command = macOSAppBundleInstalled ? "/usr/bin/open" : _vsCodePath; } else { diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs index 3f1d5ac3ca..7a0983a8cb 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs @@ -30,7 +30,7 @@ namespace GodotTools.Ides.MonoDevelop { string bundleId = BundleIds[_editorId]; - if (Internal.IsOsxAppBundleInstalled(bundleId)) + if (Internal.IsMacOSAppBundleInstalled(bundleId)) { command = "open"; diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index 77370090ec..12c90178c9 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -12,12 +12,12 @@ namespace GodotTools.Internals public static string UpdateApiAssembliesFromPrebuilt(string config) => internal_UpdateApiAssembliesFromPrebuilt(config); - public static string FullTemplatesDir => - internal_FullTemplatesDir(); + public static string FullExportTemplatesDir => + internal_FullExportTemplatesDir(); public static string SimplifyGodotPath(this string path) => internal_SimplifyGodotPath(path); - public static bool IsOsxAppBundleInstalled(string bundleId) => internal_IsOsxAppBundleInstalled(bundleId); + public static bool IsMacOSAppBundleInstalled(string bundleId) => internal_IsMacOSAppBundleInstalled(bundleId); public static bool GodotIs32Bits() => internal_GodotIs32Bits(); @@ -57,13 +57,13 @@ namespace GodotTools.Internals private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern string internal_FullTemplatesDir(); + private static extern string internal_FullExportTemplatesDir(); [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_SimplifyGodotPath(this string path); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool internal_IsOsxAppBundleInstalled(string bundleId); + private static extern bool internal_IsMacOSAppBundleInstalled(string bundleId); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool internal_GodotIs32Bits(); diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index 2db549c623..5cef6e5c3c 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -37,13 +37,13 @@ namespace GodotTools.Utils public static class Platforms { public const string Windows = "windows"; - public const string MacOS = "osx"; + public const string MacOS = "macos"; public const string LinuxBSD = "linuxbsd"; public const string Server = "server"; public const string UWP = "uwp"; public const string Haiku = "haiku"; public const string Android = "android"; - public const string iOS = "iphone"; + public const string iOS = "ios"; public const string HTML5 = "javascript"; } diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index f7f710f3f1..5e4fe90553 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -47,7 +47,7 @@ #include "../glue/cs_glue_version.gen.h" #include "../godotsharp_dirs.h" #include "../mono_gd/gd_mono_marshal.h" -#include "../utils/osx_utils.h" +#include "../utils/macos_utils.h" #include "code_completion.h" #include "godotsharp_export.h" @@ -188,8 +188,8 @@ MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_c return GDMonoMarshal::mono_string_from_godot(error_str); } -MonoString *godot_icall_Internal_FullTemplatesDir() { - String full_templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); +MonoString *godot_icall_Internal_FullExportTemplatesDir() { + String full_templates_dir = EditorSettings::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG); return GDMonoMarshal::mono_string_from_godot(full_templates_dir); } @@ -198,10 +198,10 @@ MonoString *godot_icall_Internal_SimplifyGodotPath(MonoString *p_path) { return GDMonoMarshal::mono_string_from_godot(path.simplify_path()); } -MonoBoolean godot_icall_Internal_IsOsxAppBundleInstalled(MonoString *p_bundle_id) { -#ifdef OSX_ENABLED +MonoBoolean godot_icall_Internal_IsMacOSAppBundleInstalled(MonoString *p_bundle_id) { +#ifdef MACOS_ENABLED String bundle_id = GDMonoMarshal::mono_string_to_godot(p_bundle_id); - return (MonoBoolean)osx_is_app_bundle_installed(bundle_id); + return (MonoBoolean)macos_is_app_bundle_installed(bundle_id); #else (void)p_bundle_id; // UNUSED return (MonoBoolean) false; @@ -364,9 +364,9 @@ void register_editor_internal_calls() { // Internals GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt); - GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", godot_icall_Internal_FullTemplatesDir); + GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullExportTemplatesDir", godot_icall_Internal_FullExportTemplatesDir); GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath); - GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", godot_icall_Internal_IsOsxAppBundleInstalled); + GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsMacOSAppBundleInstalled", godot_icall_Internal_IsMacOSAppBundleInstalled); GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits); GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble); GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 63af1c5892..fd97a71e47 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -118,15 +118,15 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if point is inside the plane. - /// Comparison uses a custom minimum epsilon threshold. + /// Comparison uses a custom minimum tolerance threshold. /// </summary> /// <param name="point">The point to check.</param> - /// <param name="epsilon">The tolerance threshold.</param> + /// <param name="tolerance">The tolerance threshold.</param> /// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns> - public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) + public bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon) { real_t dist = _normal.Dot(point) - D; - return Mathf.Abs(dist) <= epsilon; + return Mathf.Abs(dist) <= tolerance; } /// <summary> diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index cb2b60fcce..f17b24e399 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -184,7 +184,7 @@ private: data_mono_bin_dir = data_mono_root_dir.plus_file("bin"); #endif -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED if (!DirAccess::exists(data_editor_tools_dir)) { data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools"); } @@ -222,7 +222,7 @@ private: data_mono_bin_dir = data_mono_root_dir.plus_file("bin"); #endif -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED if (!DirAccess::exists(data_mono_root_dir)) { data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc"); data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib"); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 39a8ef22b7..d3d3bb2bef 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -55,7 +55,7 @@ #ifdef ANDROID_ENABLED #include "android_mono_config.h" #include "support/android_support.h" -#elif defined(IPHONE_ENABLED) +#elif defined(IOS_ENABLED) #include "support/ios_support.h" #endif @@ -188,7 +188,7 @@ MonoDomain *gd_initialize_mono_runtime() { MonoDomain *gd_initialize_mono_runtime() { gd_mono_debug_init(); -#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED) +#if defined(IOS_ENABLED) || defined(ANDROID_ENABLED) // I don't know whether this actually matters or not const char *runtime_version = "mobile"; #else @@ -263,7 +263,7 @@ void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_di if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) { r_config_dir = mono_reg_info.config_dir; } -#elif defined(OSX_ENABLED) +#elif defined(MACOS_ENABLED) const char *c_assembly_rootdir = mono_assembly_getrootdir(); const char *c_config_dir = mono_get_config_dir(); @@ -343,7 +343,7 @@ void GDMono::initialize() { #if defined(ANDROID_ENABLED) gdmono::android::support::initialize(); -#elif defined(IPHONE_ENABLED) +#elif defined(IOS_ENABLED) gdmono::ios::support::initialize(); #endif diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index 9fc35f8e31..93ba6a410e 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -35,7 +35,7 @@ #include "core/typedefs.h" -#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED) +#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED) // We have custom mono log callbacks for WASM and iOS #define GD_MONO_LOG_ENABLED #endif diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h index bb163b89bc..0180dee3ea 100644 --- a/modules/mono/mono_gd/gd_mono_method_thunk.h +++ b/modules/mono/mono_gd/gd_mono_method_thunk.h @@ -39,7 +39,7 @@ #include "gd_mono_method.h" #include "gd_mono_utils.h" -#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED) +#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED) #define HAVE_METHOD_THUNKS #endif diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h index 2f444d5089..03e86df698 100644 --- a/modules/mono/mono_gd/support/ios_support.h +++ b/modules/mono/mono_gd/support/ios_support.h @@ -31,7 +31,7 @@ #ifndef IOS_SUPPORT_H #define IOS_SUPPORT_H -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) #include "core/string/ustring.h" @@ -45,6 +45,6 @@ void cleanup(); } // namespace ios } // namespace gdmono -#endif // IPHONE_ENABLED +#endif // IOS_ENABLED #endif // IOS_SUPPORT_H diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm index df97dfba49..7c941b9d1e 100644 --- a/modules/mono/mono_gd/support/ios_support.mm +++ b/modules/mono/mono_gd/support/ios_support.mm @@ -30,7 +30,7 @@ #include "ios_support.h" -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) #import <Foundation/Foundation.h> #include <os/log.h> @@ -147,4 +147,4 @@ GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) { os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'"); } -#endif // IPHONE_ENABLED +#endif // IOS_ENABLED diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/macos_utils.cpp index abb59420eb..cd4f7a827e 100644 --- a/modules/mono/utils/osx_utils.cpp +++ b/modules/mono/utils/macos_utils.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_utils.cpp */ +/* macos_utils.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "osx_utils.h" +#include "macos_utils.h" -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #include "core/string/print_string.h" #import <CoreFoundation/CoreFoundation.h> #import <CoreServices/CoreServices.h> -bool osx_is_app_bundle_installed(const String &p_bundle_id) { +bool macos_is_app_bundle_installed(const String &p_bundle_id) { CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8); CFArrayRef result = LSCopyApplicationURLsForBundleIdentifier(bundle_id, nullptr); CFRelease(bundle_id); diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/macos_utils.h index 2f6c6dad51..7892cb2785 100644 --- a/modules/mono/utils/osx_utils.h +++ b/modules/mono/utils/macos_utils.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_utils.h */ +/* macos_utils.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,13 +30,13 @@ #include "core/string/ustring.h" -#ifndef OSX_UTILS_H -#define OSX_UTILS_H +#ifndef MACOS_UTILS_H +#define MACOS_UTILS_H -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED -bool osx_is_app_bundle_installed(const String &p_bundle_id); +bool macos_is_app_bundle_installed(const String &p_bundle_id); #endif -#endif // OSX_UTILS_H +#endif // MACOS_UTILS_H diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index da52ecfdd5..e18fa9e590 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -106,7 +106,7 @@ float OGGPacketSequence::get_length() const { return granule_pos / sampling_rate; } -Ref<OGGPacketSequencePlayback> OGGPacketSequence::instance_playback() { +Ref<OGGPacketSequencePlayback> OGGPacketSequence::instantiate_playback() { Ref<OGGPacketSequencePlayback> playback; playback.instantiate(); playback->ogg_packet_sequence = Ref<OGGPacketSequence>(this); diff --git a/modules/ogg/ogg_packet_sequence.h b/modules/ogg/ogg_packet_sequence.h index 73e3cb4fff..76b673c6ac 100644 --- a/modules/ogg/ogg_packet_sequence.h +++ b/modules/ogg/ogg_packet_sequence.h @@ -86,7 +86,7 @@ public: // Returns the granule position of the last page in this sequence. int64_t get_final_granule_pos() const; - Ref<OGGPacketSequencePlayback> instance_playback(); + Ref<OGGPacketSequencePlayback> instantiate_playback(); OGGPacketSequence() {} virtual ~OGGPacketSequence() {} diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 74f708bc95..25bf496de9 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -5,10 +5,10 @@ </brief_description> <description> The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games. - Due to the needs of OpenXR this interface works slightly different then other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. + Due to the needs of OpenXR this interface works slightly different than other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset. </description> <tutorials> - <link title="OpenXR documentation">$DOCS_URL/tutorials/vr/openxr/index.html</link> + <link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link> </tutorials> <signals> <signal name="pose_recentered"> diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index dcb1f1d744..87e2fae2d0 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -80,8 +80,8 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin float fw, fh; picture->size(&fw, &fh); - uint32_t width = MIN(fw * p_scale, 16 * 1024); - uint32_t height = MIN(fh * p_scale, 16 * 1024); + uint32_t width = MIN(round(fw * p_scale), 16 * 1024); + uint32_t height = MIN(round(fh * p_scale), 16 * 1024); picture->size(width, height); std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen(); diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 69848a9e52..0170c007ae 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -624,15 +624,15 @@ env.Append(CPPDEFINES=["GDEXTENSION"]) env.Append(CPPPATH=["../"]) sources = Glob("../*.cpp") -if env["platform"] == "osx": - methods.write_osx_plist( - f'./bin/libtextserver_advanced.osx.{env["target"]}.framework', - f'libtextserver_advanced.osx.{env["target"]}', +if env["platform"] == "macos": + methods.write_macos_plist( + f'./bin/libtextserver_advanced.macos.{env["target"]}.framework', + f'libtextserver_advanced.macos.{env["target"]}', "org.godotengine.textserver_advanced", "ICU / HarfBuzz / Graphite Text Server", ) library = env.SharedLibrary( - f'./bin/libtextserver_advanced.osx.{env["target"]}.framework/libtextserver_advanced.osx.{env["target"]}', + f'./bin/libtextserver_advanced.macos.{env["target"]}.framework/libtextserver_advanced.macos.{env["target"]}', source=sources, ) else: diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py index d404f2851e..3c5229462c 100644 --- a/modules/text_server_adv/gdextension_build/methods.py +++ b/modules/text_server_adv/gdextension_build/methods.py @@ -98,7 +98,7 @@ def make_icu_data(target, source, env): g.write("#endif") -def write_osx_plist(target, binary_name, identifier, name): +def write_macos_plist(target, binary_name, identifier, name): os.makedirs(f"{target}/Resourece/", exist_ok=True) f = open(f"{target}/Resourece/Info.plist", "w") diff --git a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension index 5956476a5e..11ed271ae9 100644 --- a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension +++ b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension @@ -8,5 +8,5 @@ linux.64.debug = "bin/libtextserver_advanced.linux.debug.64.so" linux.64.release = "bin/libtextserver_advanced.linux.release.64.so" windows.64.debug = "bin/libtextserver_advanced.windows.debug.64.dll" windows.64.release = "bin/libtextserver_advanced.windows.release.64.dll" -macos.debug = "bin/libtextserver_advanced.osx.debug.framework" -macos.release = "bin/libtextserver_advanced.osx.release.framework" +macos.debug = "bin/libtextserver_advanced.macos.debug.framework" +macos.release = "bin/libtextserver_advanced.macos.release.framework" diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 6c9e10db18..de0a549900 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -184,15 +184,15 @@ env.Append(CPPDEFINES=["GDEXTENSION"]) env.Append(CPPPATH=["../"]) sources = Glob("../*.cpp") -if env["platform"] == "osx": - methods.write_osx_plist( - f'./bin/libtextserver_fallback.osx.{env["target"]}.framework', - f'libtextserver_fallback.osx.{env["target"]}', +if env["platform"] == "macos": + methods.write_macos_plist( + f'./bin/libtextserver_fallback.macos.{env["target"]}.framework', + f'libtextserver_fallback.macos.{env["target"]}', "org.godotengine.textserver_fallback", "Fallback Text Server", ) library = env.SharedLibrary( - f'./bin/libtextserver_fallback.osx.{env["target"]}.framework/libtextserver_fallback.osx.{env["target"]}', + f'./bin/libtextserver_fallback.macos.{env["target"]}.framework/libtextserver_fallback.macos.{env["target"]}', source=sources, ) else: diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py index d404f2851e..3c5229462c 100644 --- a/modules/text_server_fb/gdextension_build/methods.py +++ b/modules/text_server_fb/gdextension_build/methods.py @@ -98,7 +98,7 @@ def make_icu_data(target, source, env): g.write("#endif") -def write_osx_plist(target, binary_name, identifier, name): +def write_macos_plist(target, binary_name, identifier, name): os.makedirs(f"{target}/Resourece/", exist_ok=True) f = open(f"{target}/Resourece/Info.plist", "w") diff --git a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension index 1026c6cb85..9236555d63 100644 --- a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension +++ b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension @@ -8,5 +8,5 @@ linux.64.debug = "bin/libtextserver_fallback.linux.debug.64.so" linux.64.release = "bin/libtextserver_fallback.linux.release.64.so" windows.64.debug = "bin/libtextserver_fallback.windows.debug.64.dll" windows.64.release = "bin/libtextserver_fallback.windows.release.64.dll" -macos.debug = "bin/libtextserver_fallback.osx.debug.framework" -macos.release = "bin/libtextserver_fallback.osx.release.framework" +macos.debug = "bin/libtextserver_fallback.macos.debug.framework" +macos.release = "bin/libtextserver_fallback.macos.release.framework" diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 8940ed6aff..dd69bf066a 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -170,7 +170,7 @@ protected: static void _bind_methods(); public: - Ref<VideoStreamPlayback> instance_playback() override { + Ref<VideoStreamPlayback> instantiate_playback() override { Ref<VideoStreamPlaybackTheora> pb = memnew(VideoStreamPlaybackTheora); pb->set_audio_track(audio_track); pb->set_file(file); diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 61ff56b62a..522ed8719b 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -1227,7 +1227,7 @@ void VisualScriptEditor::_member_selected() { selected = ti->get_metadata(0); if (ti->get_parent() == members->get_root()->get_first_child()) { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META); #else bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); @@ -2208,7 +2208,7 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant & String(d["type"]) == "files" || String(d["type"]) == "nodes")) { if (String(d["type"]) == "obj_property") { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Getter. Hold Shift to drop a generic signature."), find_keycode_name(Key::META))); #else const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature.")); @@ -2216,7 +2216,7 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant & } if (String(d["type"]) == "nodes") { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a simple reference to the node."), find_keycode_name(Key::META))); #else const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node.")); @@ -2224,7 +2224,7 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant & } if (String(d["type"]) == "visual_script_variable_drag") { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Variable Setter."), find_keycode_name(Key::META))); #else const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter.")); @@ -2287,7 +2287,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "visual_script_variable_drag") { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_set = Input::get_singleton()->is_key_pressed(Key::META); #else bool use_set = Input::get_singleton()->is_key_pressed(Key::CTRL); @@ -2396,7 +2396,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "files") { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_preload = Input::get_singleton()->is_key_pressed(Key::META); #else bool use_preload = Input::get_singleton()->is_key_pressed(Key::CTRL); @@ -2459,7 +2459,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da return; } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_node = Input::get_singleton()->is_key_pressed(Key::META); #else bool use_node = Input::get_singleton()->is_key_pressed(Key::CTRL); @@ -2524,7 +2524,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da Node *node = Object::cast_to<Node>(obj); Vector2 pos = _get_pos_in_graph(p_point); -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_get = Input::get_singleton()->is_key_pressed(Key::META); #else bool use_get = Input::get_singleton()->is_key_pressed(Key::CTRL); @@ -3378,7 +3378,7 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua } void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META); #else bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 89a6b03ff8..76f7317daa 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -43,28 +43,93 @@ int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram int todo = p_frames; - int start_buffer = 0; + int beat_length_frames = -1; + bool beat_loop = vorbis_stream->has_loop(); + if (beat_loop && vorbis_stream->get_bpm() > 0 && vorbis_stream->get_beat_count() > 0) { + beat_length_frames = vorbis_stream->get_beat_count() * vorbis_data->get_sampling_rate() * 60 / vorbis_stream->get_bpm(); + } while (todo > 0 && active) { AudioFrame *buffer = p_buffer; - if (start_buffer > 0) { - buffer = buffer + start_buffer; + buffer += p_frames - todo; + + int to_mix = todo; + if (beat_length_frames >= 0 && (beat_length_frames - (int)frames_mixed) < to_mix) { + to_mix = MAX(0, beat_length_frames - (int)frames_mixed); } - int mixed = _mix_frames_vorbis(buffer, todo); + + int mixed = _mix_frames_vorbis(buffer, to_mix); ERR_FAIL_COND_V(mixed < 0, 0); todo -= mixed; frames_mixed += mixed; - start_buffer += mixed; + + if (loop_fade_remaining < FADE_SIZE) { + int to_fade = loop_fade_remaining + MIN(FADE_SIZE - loop_fade_remaining, mixed); + for (int i = loop_fade_remaining; i < to_fade; i++) { + buffer[i - loop_fade_remaining] += loop_fade[i] * (float(FADE_SIZE - i) / float(FADE_SIZE)); + } + loop_fade_remaining = to_fade; + } + + if (beat_length_frames >= 0) { + /** + * Length determined by beat length + * This code is commented out because, in practice, it is prefered that the fade + * is done by the transitioner and this stream just goes on until it ends while fading out. + * + * End fade implementation is left here for reference in case at some point this feature + * is desired. + + if (!beat_loop && (int)frames_mixed > beat_length_frames - FADE_SIZE) { + print_line("beat length fade/after mix?"); + //No loop, just fade and finish + for (int i = 0; i < mixed; i++) { + int idx = frames_mixed + i - mixed; + buffer[i] *= 1.0 - float(MAX(0, (idx - (beat_length_frames - FADE_SIZE)))) / float(FADE_SIZE); + } + if ((int)frames_mixed == beat_length_frames) { + for (int i = p_frames - todo; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0, 0); + } + active = false; + break; + } + } else + **/ + + if (beat_loop && beat_length_frames <= (int)frames_mixed) { + // End of file when doing beat-based looping. <= used instead of == because importer editing + if (!have_packets_left && !have_samples_left) { + //Nothing remaining, so do nothing. + loop_fade_remaining = FADE_SIZE; + } else { + // Add some loop fade; + int faded_mix = _mix_frames_vorbis(loop_fade, FADE_SIZE); + + for (int i = faded_mix; i < FADE_SIZE; i++) { + // In case lesss was mixed, pad with zeros + loop_fade[i] = AudioFrame(0, 0); + } + loop_fade_remaining = 0; + } + + seek(vorbis_stream->loop_offset); + loops++; + // We still have buffer to fill, start from this element in the next iteration. + continue; + } + } + if (!have_packets_left && !have_samples_left) { - //end of file! + // Actual end of file! bool is_not_empty = mixed > 0 || vorbis_stream->get_length() > 0; if (vorbis_stream->loop && is_not_empty) { //loop seek(vorbis_stream->loop_offset); loops++; - // we still have buffer to fill, start from this element in the next iteration. - start_buffer = p_frames - todo; + // We still have buffer to fill, start from this element in the next iteration. + } else { for (int i = p_frames - todo; i < p_frames; i++) { p_buffer[i] = AudioFrame(0, 0); @@ -130,7 +195,7 @@ bool AudioStreamPlaybackOGGVorbis::_alloc_vorbis() { comment_is_allocated = true; ERR_FAIL_COND_V(vorbis_data.is_null(), false); - vorbis_data_playback = vorbis_data->instance_playback(); + vorbis_data_playback = vorbis_data->instantiate_playback(); ogg_packet *packet; int err; @@ -160,6 +225,7 @@ bool AudioStreamPlaybackOGGVorbis::_alloc_vorbis() { void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) { ERR_FAIL_COND(!ready); + loop_fade_remaining = FADE_SIZE; active = true; seek(p_from_pos); loops = 0; @@ -182,6 +248,10 @@ float AudioStreamPlaybackOGGVorbis::get_playback_position() const { return float(frames_mixed) / vorbis_data->get_sampling_rate(); } +void AudioStreamPlaybackOGGVorbis::tag_used_streams() { + vorbis_stream->tag_used(get_playback_position()); +} + void AudioStreamPlaybackOGGVorbis::seek(float p_time) { ERR_FAIL_COND(!ready); ERR_FAIL_COND(vorbis_stream.is_null()); @@ -315,7 +385,7 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { } } -Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { +Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instantiate_playback() { Ref<AudioStreamPlaybackOGGVorbis> ovs; ERR_FAIL_COND_V(packet_sequence.is_null(), nullptr); @@ -347,7 +417,7 @@ void AudioStreamOGGVorbis::maybe_update_info() { vorbis_info_init(&info); vorbis_comment_init(&comment); - Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instance_playback(); + Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instantiate_playback(); for (int i = 0; i < 3; i++) { ogg_packet *packet; @@ -405,6 +475,36 @@ float AudioStreamOGGVorbis::get_length() const { return packet_sequence->get_length(); } +void AudioStreamOGGVorbis::set_bpm(double p_bpm) { + ERR_FAIL_COND(p_bpm < 0); + bpm = p_bpm; + emit_changed(); +} + +double AudioStreamOGGVorbis::get_bpm() const { + return bpm; +} + +void AudioStreamOGGVorbis::set_beat_count(int p_beat_count) { + ERR_FAIL_COND(p_beat_count < 0); + beat_count = p_beat_count; + emit_changed(); +} + +int AudioStreamOGGVorbis::get_beat_count() const { + return beat_count; +} + +void AudioStreamOGGVorbis::set_bar_beats(int p_bar_beats) { + ERR_FAIL_COND(p_bar_beats < 2); + bar_beats = p_bar_beats; + emit_changed(); +} + +int AudioStreamOGGVorbis::get_bar_beats() const { + return bar_beats; +} + bool AudioStreamOGGVorbis::is_monophonic() const { return false; } @@ -419,7 +519,19 @@ void AudioStreamOGGVorbis::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset); ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset); + ClassDB::bind_method(D_METHOD("set_bpm", "bpm"), &AudioStreamOGGVorbis::set_bpm); + ClassDB::bind_method(D_METHOD("get_bpm"), &AudioStreamOGGVorbis::get_bpm); + + ClassDB::bind_method(D_METHOD("set_beat_count", "count"), &AudioStreamOGGVorbis::set_beat_count); + ClassDB::bind_method(D_METHOD("get_beat_count"), &AudioStreamOGGVorbis::get_beat_count); + + ClassDB::bind_method(D_METHOD("set_bar_beats", "count"), &AudioStreamOGGVorbis::set_bar_beats); + ClassDB::bind_method(D_METHOD("get_bar_beats"), &AudioStreamOGGVorbis::get_bar_beats); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packet_sequence", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_sequence", "get_packet_sequence"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), "set_bpm", "get_bpm"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,1,or_greater"), "set_beat_count", "get_beat_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,1,or_greater"), "set_bar_beats", "get_bar_beats"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset"); } diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index b09ef9ff5d..22c2eb4d73 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -45,6 +45,12 @@ class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled { bool active = false; int loops = 0; + enum { + FADE_SIZE = 256 + }; + AudioFrame loop_fade[FADE_SIZE]; + int loop_fade_remaining = FADE_SIZE; + vorbis_info info; vorbis_comment comment; vorbis_dsp_state dsp_state; @@ -66,6 +72,7 @@ class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled { Ref<OGGPacketSequencePlayback> vorbis_data_playback; Ref<AudioStreamOGGVorbis> vorbis_stream; + int _mix_frames(AudioFrame *p_buffer, int p_frames); int _mix_frames_vorbis(AudioFrame *p_buffer, int p_frames); // Allocates vorbis data structures. Returns true upon success, false on failure. @@ -85,6 +92,8 @@ public: virtual float get_playback_position() const override; virtual void seek(float p_time) override; + virtual void tag_used_streams() override; + AudioStreamPlaybackOGGVorbis() {} ~AudioStreamPlaybackOGGVorbis(); }; @@ -107,17 +116,30 @@ class AudioStreamOGGVorbis : public AudioStream { Ref<OGGPacketSequence> packet_sequence; + double bpm = 0; + int beat_count = 0; + int bar_beats = 4; + protected: static void _bind_methods(); public: void set_loop(bool p_enable); - bool has_loop() const; + virtual bool has_loop() const override; void set_loop_offset(float p_seconds); float get_loop_offset() const; - virtual Ref<AudioStreamPlayback> instance_playback() override; + void set_bpm(double p_bpm); + virtual double get_bpm() const override; + + void set_beat_count(int p_beat_count); + virtual int get_beat_count() const override; + + void set_bar_beats(int p_bar_beats); + virtual int get_bar_beats() const override; + + virtual Ref<AudioStreamPlayback> instantiate_playback() override; virtual String get_stream_name() const override; void set_packet_sequence(Ref<OGGPacketSequence> p_packet_sequence); diff --git a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml index 2f210a6cb4..f87296dcd8 100644 --- a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -7,6 +7,12 @@ <tutorials> </tutorials> <members> + <member name="bar_beats" type="int" setter="set_bar_beats" getter="get_bar_beats" default="4"> + </member> + <member name="beat_count" type="int" setter="set_beat_count" getter="get_beat_count" default="0"> + </member> + <member name="bpm" type="float" setter="set_bpm" getter="get_bpm" default="0.0"> + </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> If [code]true[/code], the stream will automatically loop when it reaches the end. </member> diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index 7ee6446313..9461d531fd 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -30,13 +30,16 @@ #include "resource_importer_ogg_vorbis.h" -#include "audio_stream_ogg_vorbis.h" #include "core/io/file_access.h" #include "core/io/resource_saver.h" #include "scene/resources/texture.h" #include "thirdparty/libogg/ogg/ogg.h" #include "thirdparty/libvorbis/vorbis/codec.h" +#ifdef TOOLS_ENABLED +#include "editor/import/audio_stream_import_settings.h" +#endif + String ResourceImporterOGGVorbis::get_importer_name() const { return "oggvorbisstr"; } @@ -72,14 +75,14 @@ String ResourceImporterOGGVorbis::get_preset_name(int p_idx) const { void ResourceImporterOGGVorbis::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,or_greater"), 4)); } -Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - bool loop = p_options["loop"]; - float loop_offset = p_options["loop_offset"]; - - Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); - ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); +Ref<AudioStreamOGGVorbis> ResourceImporterOGGVorbis::import_ogg_vorbis(const String &p_path) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), Ref<AudioStreamOGGVorbis>(), "Cannot open file '" + p_path + "'."); uint64_t len = f->get_length(); @@ -107,16 +110,16 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin size_t packet_count = 0; bool done = false; while (!done) { - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOGGVorbis>(), "Ogg sync error " + itos(err)); while (ogg_sync_pageout(&sync_state, &page) != 1) { if (cursor >= len) { done = true; break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOGGVorbis>(), "Ogg sync error " + itos(err)); char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE); - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); - ERR_FAIL_COND_V(cursor > len, Error::ERR_INVALID_DATA); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOGGVorbis>(), "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V(cursor > len, Ref<AudioStreamOGGVorbis>()); size_t copy_size = len - cursor; if (copy_size > OGG_SYNC_BUFFER_SIZE) { copy_size = OGG_SYNC_BUFFER_SIZE; @@ -124,22 +127,22 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin memcpy(sync_buf, &file_data[cursor], copy_size); ogg_sync_wrote(&sync_state, copy_size); cursor += copy_size; - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOGGVorbis>(), "Ogg sync error " + itos(err)); } if (done) { break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOGGVorbis>(), "Ogg sync error " + itos(err)); // Have a page now. if (!initialized_stream) { if (ogg_stream_init(&stream_state, ogg_page_serialno(&page))) { - ERR_FAIL_V_MSG(Error::ERR_OUT_OF_MEMORY, "Failed allocating memory for OGG Vorbis stream."); + ERR_FAIL_V_MSG(Ref<AudioStreamOGGVorbis>(), "Failed allocating memory for OGG Vorbis stream."); } initialized_stream = true; } ogg_stream_pagein(&stream_state, &page); - ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Ref<AudioStreamOGGVorbis>(), "Ogg stream error " + itos(err)); int desync_iters = 0; Vector<Vector<uint8_t>> packet_data; @@ -150,7 +153,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin if (err == -1) { // According to the docs this is usually recoverable, but don't sit here spinning forever. desync_iters++; - ERR_FAIL_COND_V_MSG(desync_iters > 100, Error::ERR_INVALID_DATA, "Packet sync issue during ogg import"); + ERR_FAIL_COND_V_MSG(desync_iters > 100, Ref<AudioStreamOGGVorbis>(), "Packet sync issue during ogg import"); continue; } else if (err == 0) { // Not enough data to fully reconstruct a packet. Go on to the next page. @@ -183,12 +186,45 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin ogg_sync_clear(&sync_state); if (ogg_packet_sequence->get_packet_granule_positions().is_empty()) { - ERR_FAIL_V_MSG(Error::ERR_FILE_CORRUPT, "OGG Vorbis decoding failed. Check that your data is a valid OGG Vorbis audio stream."); + ERR_FAIL_V_MSG(Ref<AudioStreamOGGVorbis>(), "OGG Vorbis decoding failed. Check that your data is a valid OGG Vorbis audio stream."); } ogg_vorbis_stream->set_packet_sequence(ogg_packet_sequence); + + return ogg_vorbis_stream; +} + +#ifdef TOOLS_ENABLED + +bool ResourceImporterOGGVorbis::has_advanced_options() const { + return true; +} + +void ResourceImporterOGGVorbis::show_advanced_options(const String &p_path) { + Ref<AudioStreamOGGVorbis> ogg_stream = import_ogg_vorbis(p_path); + if (ogg_stream.is_valid()) { + AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); + } +} +#endif + +Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + bool loop = p_options["loop"]; + float loop_offset = p_options["loop_offset"]; + double bpm = p_options["bpm"]; + int beat_count = p_options["beat_count"]; + int bar_beats = p_options["bar_beats"]; + + Ref<AudioStreamOGGVorbis> ogg_vorbis_stream = import_ogg_vorbis(p_source_file); + if (ogg_vorbis_stream.is_null()) { + return ERR_CANT_OPEN; + } + ogg_vorbis_stream->set_loop(loop); ogg_vorbis_stream->set_loop_offset(loop_offset); + ogg_vorbis_stream->set_bpm(bpm); + ogg_vorbis_stream->set_beat_count(beat_count); + ogg_vorbis_stream->set_bar_beats(bar_beats); return ResourceSaver::save(p_save_path + ".oggvorbisstr", ogg_vorbis_stream); } diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 3b4a68a1fd..e6e98a29c1 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -31,6 +31,7 @@ #ifndef RESOURCE_IMPORTER_OGG_VORBIS_H #define RESOURCE_IMPORTER_OGG_VORBIS_H +#include "audio_stream_ogg_vorbis.h" #include "core/io/resource_importer.h" class ResourceImporterOGGVorbis : public ResourceImporter { @@ -43,7 +44,13 @@ class ResourceImporterOGGVorbis : public ResourceImporter { private: // virtual int get_samples_in_packet(Vector<uint8_t> p_packet) = 0; + static Ref<AudioStreamOGGVorbis> import_ogg_vorbis(const String &p_path); + public: +#ifdef TOOLS_ENABLED + virtual bool has_advanced_options() const override; + virtual void show_advanced_options(const String &p_path) override; +#endif virtual void get_recognized_extensions(List<String> *p_extensions) const override; virtual String get_save_extension() const override; virtual String get_resource_type() const override; |