diff options
Diffstat (limited to 'modules')
77 files changed, 2178 insertions, 1076 deletions
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 21ba67ecd3..796ee27a7d 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -838,7 +838,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat String ai_anim_mesh_name = AssimpUtils::get_assimp_string(ai_mesh->mAnimMeshes[j]->mName); if (!morph_mesh_string_lookup.has(ai_anim_mesh_name)) { morph_mesh_string_lookup.insert(ai_anim_mesh_name, j); - mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); + mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED); if (ai_anim_mesh_name.empty()) { ai_anim_mesh_name = String("morph_") + itos(j); } diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index cce72770f5..f8c05761bb 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -319,7 +319,7 @@ bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial); } -String CSGShape3DGizmoPlugin::get_name() const { +String CSGShape3DGizmoPlugin::get_gizmo_name() const { return "CSGShape3D"; } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 83ee847caf..cf44f76f37 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -40,7 +40,7 @@ class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { public: bool has_gizmo(Node3D *p_spatial) override; - String get_name() const override; + String get_gizmo_name() const override; int get_priority() const override; bool is_selectable_when_hidden() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_compress_etc.cpp index 4e9e64c6a7..bcdea41b43 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_compress_etc.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_etc.cpp */ +/* image_compress_etc.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "image_etc.h" -#include "Etc.h" -#include "EtcFilter.h" +#include "image_compress_etc.h" + #include "core/io/image.h" #include "core/os/copymem.h" #include "core/os/os.h" #include "core/string/print_string.h" +#include <Etc.h> +#include <EtcFilter.h> + static Image::Format _get_etc2_mode(Image::UsedChannels format) { switch (format) { case Image::USED_CHANNELS_R: diff --git a/modules/etc/image_etc.h b/modules/etc/image_compress_etc.h index 7b4f26e127..016e64e4fc 100644 --- a/modules/etc/image_etc.h +++ b/modules/etc/image_compress_etc.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* image_etc.h */ +/* image_compress_etc.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IMAGE_ETC1_H -#define IMAGE_ETC1_H +#ifndef IMAGE_COMPRESS_ETC_H +#define IMAGE_COMPRESS_ETC_H void _register_etc_compress_func(); -#endif // IMAGE_ETC_H +#endif // IMAGE_COMPRESS_ETC_H diff --git a/modules/etc/register_types.cpp b/modules/etc/register_types.cpp index 0972857808..225ba6b954 100644 --- a/modules/etc/register_types.cpp +++ b/modules/etc/register_types.cpp @@ -30,7 +30,7 @@ #include "register_types.h" -#include "image_etc.h" +#include "image_compress_etc.h" #include "texture_loader_pkm.h" static Ref<ResourceFormatPKM> resource_loader_pkm; diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp index f0f095ddf5..719fcbc927 100644 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ b/modules/gdnative/gdnative_library_editor_plugin.cpp @@ -308,11 +308,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { platform_android.library_extension = "*.so"; platforms["Android"] = platform_android; - // TODO: Javascript platform is not supported yet - // NativePlatformConfig platform_html5; - // platform_html5.name = "HTML5"; - // platform_html5.library_extension = "*.wasm"; - // platforms["Javascript"] = platform_html5; + NativePlatformConfig platform_html5; + platform_html5.name = "HTML5"; + platform_html5.entries.push_back("wasm32"); + platform_html5.library_extension = "*.wasm"; + platforms["HTML5"] = platform_html5; NativePlatformConfig platform_ios; platform_ios.name = "iOS"; diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h index 406c3ba663..e4b1fd5eb0 100644 --- a/modules/gdnative/include/pluginscript/godot_pluginscript.h +++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h @@ -72,6 +72,7 @@ typedef struct { godot_string_name name; godot_bool is_tool; godot_string_name base; + godot_string icon_path; // Member lines format: {<string>: <int>} godot_dictionary member_lines; @@ -127,6 +128,7 @@ typedef struct { const char **string_delimiters; // nullptr terminated array godot_bool has_named_classes; godot_bool supports_builtin_mode; + godot_bool can_inherit_from_file; godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name); godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions); diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h index 2eac6adfb5..6885f2463d 100644 --- a/modules/gdnative/include/text/godot_text.h +++ b/modules/gdnative/include/text/godot_text.h @@ -82,6 +82,9 @@ typedef struct { void (*font_set_antialiased)(void *, godot_rid *, bool); bool (*font_get_antialiased)(void *, godot_rid *); godot_dictionary (*font_get_feature_list)(void *, godot_rid *); + godot_dictionary (*font_get_variation_list)(void *, godot_rid *); + void (*font_set_variation)(void *, godot_rid *, const godot_string *, double); + double (*font_get_variation)(void *, godot_rid *, const godot_string *); void (*font_set_distance_field_hint)(void *, godot_rid *, bool); bool (*font_get_distance_field_hint)(void *, godot_rid *); void (*font_set_hinting)(void *, godot_rid *, godot_int); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index fc9c4ebd77..df685e716f 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -142,6 +142,10 @@ bool PluginScriptLanguage::supports_builtin_mode() const { return _desc.supports_builtin_mode; } +bool PluginScriptLanguage::can_inherit_from_file() const { + return _desc.can_inherit_from_file; +} + int PluginScriptLanguage::find_function(const String &p_function, const String &p_code) const { if (_desc.find_function) { return _desc.find_function(_data, (godot_string *)&p_function, (godot_string *)&p_code); @@ -398,6 +402,32 @@ void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool #endif } +bool PluginScriptLanguage::handles_global_class_type(const String &p_type) const { + return p_type == "PluginScript"; +} + +String PluginScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { + if (!p_path.empty()) { + Ref<PluginScript> script = ResourceLoader::load(p_path, "PluginScript"); + if (script.is_valid()) { + if (r_base_type) { + *r_base_type = script->get_instance_base_type(); + } + if (r_icon_path) { + *r_icon_path = script->get_script_class_icon_path(); + } + return script->get_script_class_name(); + } + if (r_base_type) { + *r_base_type = String(); + } + if (r_icon_path) { + *r_icon_path = String(); + } + } + return String(); +} + void PluginScriptLanguage::lock() { _lock.lock(); } diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 53e1e3ae9b..7548eba4a0 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -78,7 +78,7 @@ public: virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; - virtual bool can_inherit_from_file() { return true; } + virtual bool can_inherit_from_file() const; virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint); @@ -122,6 +122,11 @@ public: virtual void frame(); + /* GLOBAL CLASSES */ + + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; + void lock(); void unlock(); diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 87c6288806..d69ab2fcb7 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -302,6 +302,7 @@ Error PluginScript::reload(bool p_keep_state) { _data = manifest.data; _name = *(StringName *)&manifest.name; _tool = manifest.is_tool; + _icon_path = *(String *)&manifest.icon_path; Dictionary *members = (Dictionary *)&manifest.member_lines; for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) { diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h index dc1ed6d576..12d93cc407 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -69,6 +69,7 @@ private: String _source; String _path; StringName _name; + String _icon_path; protected: static void _bind_methods(); @@ -84,6 +85,14 @@ protected: virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; #endif public: + String get_script_class_name() const { + return _name; + } + + String get_script_class_icon_path() const { + return _icon_path; + } + virtual bool can_instance() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp index 68624260a6..cb87adafe8 100644 --- a/modules/gdnative/text/text_server_gdnative.cpp +++ b/modules/gdnative/text/text_server_gdnative.cpp @@ -148,6 +148,24 @@ bool TextServerGDNative::font_get_antialiased(RID p_font) const { return interface->font_get_antialiased(data, (godot_rid *)&p_font); } +Dictionary TextServerGDNative::font_get_variation_list(RID p_font) const { + ERR_FAIL_COND_V(interface == nullptr, Dictionary()); + godot_dictionary result = interface->font_get_variation_list(data, (godot_rid *)&p_font); + Dictionary info = *(Dictionary *)&result; + godot_dictionary_destroy(&result); + + return info; +} + +void TextServerGDNative::font_set_variation(RID p_font, const String &p_name, double p_value) { + ERR_FAIL_COND(interface == nullptr); + interface->font_set_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name, p_value); +} + +double TextServerGDNative::font_get_variation(RID p_font, const String &p_name) const { + return interface->font_get_variation(data, (godot_rid *)&p_font, (godot_string *)&p_name); +} + void TextServerGDNative::font_set_hinting(RID p_font, TextServer::Hinting p_hinting) { ERR_FAIL_COND(interface == nullptr); interface->font_set_hinting(data, (godot_rid *)&p_font, (godot_int)p_hinting); diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h index 0196120c00..959302aaf4 100644 --- a/modules/gdnative/text/text_server_gdnative.h +++ b/modules/gdnative/text/text_server_gdnative.h @@ -76,6 +76,10 @@ public: virtual bool font_get_antialiased(RID p_font) const override; virtual Dictionary font_get_feature_list(RID p_font) const override; + virtual Dictionary font_get_variation_list(RID p_font) const override; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override; + virtual double font_get_variation(RID p_font, const String &p_name) const override; virtual void font_set_hinting(RID p_font, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font) const override; diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp index 7919e6a01f..c8c1b422e8 100644 --- a/modules/gdnavigation/nav_map.cpp +++ b/modules/gdnavigation/nav_map.cpp @@ -707,7 +707,7 @@ void NavMap::sync() { } if (regenerate_links) { - map_update_id = map_update_id + 1 % 9999999; + map_update_id = (map_update_id + 1) % 9999999; } if (agents_dirty) { diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp index 5329600e39..3310123ca9 100644 --- a/modules/gdnavigation/navigation_mesh_generator.cpp +++ b/modules/gdnavigation/navigation_mesh_generator.cpp @@ -176,10 +176,10 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { - Ref<CubeMesh> cube_mesh; - cube_mesh.instance(); - cube_mesh->set_size(box->get_extents() * 2.0); - mesh = cube_mesh; + Ref<BoxMesh> box_mesh; + box_mesh.instance(); + box_mesh->set_size(box->get_extents() * 2.0); + mesh = box_mesh; } CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index eeb66ebfc0..4ed129b3ff 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -763,7 +763,7 @@ <argument index="1" name="exp" type="float"> </argument> <description> - Returns the result of [code]x[/code] raised to the power of [code]y[/code]. + Returns the result of [code]base[/code] raised to the power of [code]exp[/code]. [codeblock] pow(2, 5) # Returns 32.0 [/codeblock] diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 49357f3d2e..e38647eaab 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -42,7 +42,7 @@ private: Color color; String start_key; String end_key; - bool line_only; + bool line_only = false; }; Vector<ColorRegion> color_regions; Map<int, int> color_region_cache; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 3eb260f95f..f949d26664 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -471,7 +471,7 @@ public: virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; virtual bool supports_documentation() const; - virtual bool can_inherit_from_file() { return true; } + virtual bool can_inherit_from_file() const { return true; } virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const; virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index f2d3b1fb18..e3f058886f 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -98,7 +98,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } break; case GDScriptParser::DataType::SCRIPT: { result.kind = GDScriptDataType::SCRIPT; - result.script_type = Ref<Script>(p_datatype.script_type).ptr(); + result.script_type_ref = Ref<Script>(p_datatype.script_type); + result.script_type = result.script_type_ref.ptr(); result.native_type = result.script_type->get_instance_base_type(); } break; case GDScriptParser::DataType::CLASS: { @@ -124,11 +125,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D names.pop_back(); } result.kind = GDScriptDataType::GDSCRIPT; - result.script_type = script.ptr(); + result.script_type_ref = script; + result.script_type = result.script_type_ref.ptr(); result.native_type = script->get_instance_base_type(); } else { result.kind = GDScriptDataType::GDSCRIPT; - result.script_type = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path).ptr(); + result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path); + result.script_type = result.script_type_ref.ptr(); result.native_type = p_datatype.native_type; } } @@ -151,8 +154,8 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D // Only hold strong reference to the script if it's not the owner of the // element qualified with this type, to avoid cyclic references (leaks). - if (result.script_type && result.script_type != p_owner) { - result.script_type_ref = Ref<Script>(result.script_type); + if (result.script_type && result.script_type == p_owner) { + result.script_type_ref = Ref<Script>(); } return result; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 668dfd4835..bd2d170e52 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -723,8 +723,8 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode } break; case ClassNode::Member::ENUM: { Dictionary enum_dict; - for (int j = 0; j < m.m_enum->values.size(); i++) { - enum_dict[m.m_enum->values[i].identifier->name] = m.m_enum->values[i].value; + for (int j = 0; j < m.m_enum->values.size(); j++) { + enum_dict[m.m_enum->values[j].identifier->name] = m.m_enum->values[j].value; } Dictionary api; diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 1ef991841b..66995382e7 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -447,7 +447,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i if (cell != last_cell) { //cell changed, update pointer to indices giw[cell * 2 + 1] = i; - last_cell = cell; solidw[cell] = true; } tiw[i] = triangle_sort[i].triangle_index; @@ -543,7 +542,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i tf.width = grid_size; tf.height = grid_size; tf.depth = grid_size; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; Vector<Vector<uint8_t>> texdata; @@ -695,7 +694,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d tf.width = atlas_size.width; tf.height = atlas_size.height; tf.array_layers = atlas_slices; - tf.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; @@ -826,84 +825,84 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(vertex_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(triangle_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; u.ids.push_back(box_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; u.ids.push_back(triangle_cell_indices_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; u.ids.push_back(lights_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(seams_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 7; u.ids.push_back(probe_positions_buffer); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; u.ids.push_back(grid_texture); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(grid_texture_sdf); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 10; u.ids.push_back(albedo_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 11; u.ids.push_back(emission_array_tex); base_uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 12; u.ids.push_back(sampler); base_uniforms.push_back(u); @@ -917,7 +916,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d tf.width = atlas_size.width; tf.height = atlas_size.height; tf.depth = 1; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; tf.format = RD::DATA_FORMAT_D32_SFLOAT; @@ -1049,14 +1048,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(unocclude_tex); //will be unused uniforms.push_back(u); @@ -1089,42 +1088,42 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_dest_tex); //will be unused uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(normal_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(light_primary_dynamic_tex); uniforms.push_back(u); @@ -1169,49 +1168,49 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_source_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(position_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(normal_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(unocclude_tex); //reuse unocclude tex uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; u.ids.push_back(light_environment_tex); //reuse unocclude tex uniforms.push_back(u); @@ -1317,28 +1316,28 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(light_probe_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_dest_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(light_primary_dynamic_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(light_environment_tex); uniforms.push_back(u); @@ -1463,14 +1462,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(light_accum_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(light_accum_tex2); uniforms.push_back(u); @@ -1554,7 +1553,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(light_accum_tex2); uniforms.push_back(u); diff --git a/modules/meshoptimizer/SCsub b/modules/meshoptimizer/SCsub new file mode 100644 index 0000000000..3b1a5f917e --- /dev/null +++ b/modules/meshoptimizer/SCsub @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_meshoptimizer = env_modules.Clone() + +# Thirdparty source files +thirdparty_dir = "#thirdparty/meshoptimizer/" +thirdparty_sources = [ + "allocator.cpp", + "clusterizer.cpp", + "indexcodec.cpp", + "indexgenerator.cpp", + "overdrawanalyzer.cpp", + "overdrawoptimizer.cpp", + "simplifier.cpp", + "spatialorder.cpp", + "stripifier.cpp", + "vcacheanalyzer.cpp", + "vcacheoptimizer.cpp", + "vertexcodec.cpp", + "vertexfilter.cpp", + "vfetchanalyzer.cpp", + "vfetchoptimizer.cpp", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + +env_thirdparty = env_meshoptimizer.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) + +env_modules.add_source_files(env.modules_sources, ["register_types.cpp"]) diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py new file mode 100644 index 0000000000..82e4e43397 --- /dev/null +++ b/modules/meshoptimizer/config.py @@ -0,0 +1,7 @@ +def can_build(env, platform): + # Having this on release by default, it's small and a lot of users like to do procedural stuff + return True + + +def configure(env): + pass diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp new file mode 100644 index 0000000000..26c8c6ab72 --- /dev/null +++ b/modules/meshoptimizer/register_types.cpp @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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. */ +/*************************************************************************/ + +#include "register_types.h" +#include "scene/resources/surface_tool.h" +#include "thirdparty/meshoptimizer/meshoptimizer.h" + +void register_meshoptimizer_types() { + SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache; + SurfaceTool::simplify_func = meshopt_simplify; +} + +void unregister_meshoptimizer_types() { + SurfaceTool::optimize_vertex_cache_func = nullptr; + SurfaceTool::simplify_func = nullptr; +} diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h new file mode 100644 index 0000000000..42b3a76a85 --- /dev/null +++ b/modules/meshoptimizer/register_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 MESHOPTIMIZER_REGISTER_TYPES_H +#define MESHOPTIMIZER_REGISTER_TYPES_H + +void register_meshoptimizer_types(); +void unregister_meshoptimizer_types(); + +#endif // PVR_REGISTER_TYPES_H diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub new file mode 100644 index 0000000000..f4d1605d55 --- /dev/null +++ b/modules/minimp3/SCsub @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_minimp3 = env_modules.Clone() + +thirdparty_dir = "#thirdparty/minimp3/" + +# Treat minimp3 headers as system headers to avoid raising warnings. Not supported on MSVC. +if not env.msvc: + env_minimp3.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path]) +else: + env_minimp3.Prepend(CPPPATH=[thirdparty_dir]) + +# Godot's own source files +env_minimp3.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp new file mode 100644 index 0000000000..b20c043e0c --- /dev/null +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -0,0 +1,228 @@ +/*************************************************************************/ +/* audio_stream_mp3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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. */ +/*************************************************************************/ + +#define MINIMP3_ONLY_MP3 +#define MINIMP3_FLOAT_OUTPUT +#define MINIMP3_IMPLEMENTATION +#define MINIMP3_NO_STDIO + +#include "audio_stream_mp3.h" + +#include "core/os/file_access.h" + +void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { + ERR_FAIL_COND(!active); + + int todo = p_frames; + + while (todo && active) { + mp3dec_frame_info_t frame_info; + mp3d_sample_t *buf_frame = nullptr; + + int samples_mixed = mp3dec_ex_read_frame(mp3d, &buf_frame, &frame_info, mp3_stream->channels); + + if (samples_mixed) { + p_buffer[p_frames - todo] = AudioFrame(buf_frame[0], buf_frame[samples_mixed - 1]); + --todo; + ++frames_mixed; + } + + else { + //EOF + if (mp3_stream->loop) { + seek(mp3_stream->loop_offset); + loops++; + } else { + //fill remainder with silence + for (int i = p_frames - todo; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0, 0); + } + active = false; + todo = 0; + } + } + } +} + +float AudioStreamPlaybackMP3::get_stream_sampling_rate() { + return mp3_stream->sample_rate; +} + +void AudioStreamPlaybackMP3::start(float p_from_pos) { + active = true; + seek(p_from_pos); + loops = 0; + _begin_resample(); +} + +void AudioStreamPlaybackMP3::stop() { + active = false; +} + +bool AudioStreamPlaybackMP3::is_playing() const { + return active; +} + +int AudioStreamPlaybackMP3::get_loop_count() const { + return loops; +} + +float AudioStreamPlaybackMP3::get_playback_position() const { + return float(frames_mixed) / mp3_stream->sample_rate; +} + +void AudioStreamPlaybackMP3::seek(float p_time) { + if (!active) + return; + + if (p_time >= mp3_stream->get_length()) { + p_time = 0; + } + + frames_mixed = uint32_t(mp3_stream->sample_rate * p_time); + mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels); +} + +AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { + if (mp3d) { + mp3dec_ex_close(mp3d); + memfree(mp3d); + } +} + +Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() { + Ref<AudioStreamPlaybackMP3> mp3s; + + ERR_FAIL_COND_V(data == nullptr, mp3s); + + mp3s.instance(); + mp3s->mp3_stream = Ref<AudioStreamMP3>(this); + mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t)); + + int errorcode = mp3dec_ex_open_buf(mp3s->mp3d, (const uint8_t *)data, data_len, MP3D_SEEK_TO_SAMPLE); + + mp3s->frames_mixed = 0; + mp3s->active = false; + mp3s->loops = 0; + + if (errorcode) { + ERR_FAIL_COND_V(errorcode, Ref<AudioStreamPlaybackMP3>()); + } + + return mp3s; +} + +String AudioStreamMP3::get_stream_name() const { + return ""; //return stream_name; +} + +void AudioStreamMP3::clear_data() { + if (data) { + memfree(data); + data = nullptr; + data_len = 0; + } +} + +void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) { + int src_data_len = p_data.size(); + const uint8_t *src_datar = p_data.ptr(); + + mp3dec_ex_t mp3d; + mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE); + + channels = mp3d.info.channels; + sample_rate = mp3d.info.hz; + length = float(mp3d.samples) / (sample_rate * float(channels)); + + mp3dec_ex_close(&mp3d); + + clear_data(); + + data = memalloc(src_data_len); + copymem(data, src_datar, src_data_len); + data_len = src_data_len; +} + +Vector<uint8_t> AudioStreamMP3::get_data() const { + Vector<uint8_t> vdata; + + if (data_len && data) { + vdata.resize(data_len); + { + uint8_t *w = vdata.ptrw(); + copymem(w, data, data_len); + } + } + + return vdata; +} + +void AudioStreamMP3::set_loop(bool p_enable) { + loop = p_enable; +} + +bool AudioStreamMP3::has_loop() const { + return loop; +} + +void AudioStreamMP3::set_loop_offset(float p_seconds) { + loop_offset = p_seconds; +} + +float AudioStreamMP3::get_loop_offset() const { + return loop_offset; +} + +float AudioStreamMP3::get_length() const { + return length; +} + +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); + + ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamMP3::set_loop); + ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamMP3::has_loop); + + 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); + + ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset"); +} + +AudioStreamMP3::AudioStreamMP3() { +} + +AudioStreamMP3::~AudioStreamMP3() { + clear_data(); +} diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h new file mode 100644 index 0000000000..8d67190ac5 --- /dev/null +++ b/modules/minimp3/audio_stream_mp3.h @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* audio_stream_mp3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 AUDIO_STREAM_MP3_H +#define AUDIO_STREAM_MP3_H + +#include "core/io/resource_loader.h" +#include "servers/audio/audio_stream.h" + +#include "minimp3_ex.h" + +class AudioStreamMP3; + +class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled { + GDCLASS(AudioStreamPlaybackMP3, AudioStreamPlaybackResampled); + + mp3dec_ex_t *mp3d = nullptr; + uint32_t frames_mixed = 0; + bool active = false; + int loops = 0; + + friend class AudioStreamMP3; + + Ref<AudioStreamMP3> mp3_stream; + +protected: + virtual void _mix_internal(AudioFrame *p_buffer, int p_frames) override; + virtual float get_stream_sampling_rate() override; + +public: + virtual void start(float p_from_pos = 0.0) override; + virtual void stop() override; + virtual bool is_playing() const override; + + virtual int get_loop_count() const override; //times it looped + + virtual float get_playback_position() const override; + virtual void seek(float p_time) override; + + AudioStreamPlaybackMP3() {} + ~AudioStreamPlaybackMP3(); +}; + +class AudioStreamMP3 : public AudioStream { + GDCLASS(AudioStreamMP3, AudioStream); + OBJ_SAVE_TYPE(AudioStream) //children are all saved as AudioStream, so they can be exchanged + RES_BASE_EXTENSION("mp3str"); + + friend class AudioStreamPlaybackMP3; + + void *data = nullptr; + uint32_t data_len = 0; + + float sample_rate = 1; + int channels = 1; + float length = 0; + bool loop = false; + float loop_offset = 0; + void clear_data(); + +protected: + static void _bind_methods(); + +public: + void set_loop(bool p_enable); + bool has_loop() const; + + void set_loop_offset(float p_seconds); + float get_loop_offset() const; + + virtual Ref<AudioStreamPlayback> instance_playback() override; + virtual String get_stream_name() const override; + + void set_data(const Vector<uint8_t> &p_data); + Vector<uint8_t> get_data() const; + + virtual float get_length() const override; + + AudioStreamMP3(); + virtual ~AudioStreamMP3(); +}; + +#endif // AUDIO_STREAM_MP3_H diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py new file mode 100644 index 0000000000..bd35d099b9 --- /dev/null +++ b/modules/minimp3/config.py @@ -0,0 +1,16 @@ +def can_build(env, platform): + return True + + +def configure(env): + pass + + +def get_doc_classes(): + return [ + "AudioStreamMP3", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml new file mode 100644 index 0000000000..92e777ca0f --- /dev/null +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioStreamMP3" inherits="AudioStream" version="4.0"> + <brief_description> + MP3 audio stream driver. + </brief_description> + <description> + MP3 audio stream driver. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + Contains the audio data in bytes. + </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> + <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0"> + Time in seconds at which the stream starts after being looped. + </member> + </members> + <constants> + </constants> +</class> diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp new file mode 100644 index 0000000000..2c648b8efe --- /dev/null +++ b/modules/minimp3/register_types.cpp @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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. */ +/*************************************************************************/ + +#include "register_types.h" + +#include "audio_stream_mp3.h" + +#ifdef TOOLS_ENABLED +#include "core/config/engine.h" +#include "resource_importer_mp3.h" +#endif + +void register_minimp3_types() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + Ref<ResourceImporterMP3> mp3_import; + mp3_import.instance(); + ResourceFormatImporter::get_singleton()->add_importer(mp3_import); + } +#endif + ClassDB::register_class<AudioStreamMP3>(); +} + +void unregister_minimp3_types() { +} diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h new file mode 100644 index 0000000000..0d841e4987 --- /dev/null +++ b/modules/minimp3/register_types.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 MINIMP3_REGISTER_TYPES_H +#define MINIMP3_REGISTER_TYPES_H + +void register_minimp3_types(); +void unregister_minimp3_types(); + +#endif // MINIMP3_REGISTER_TYPES_H diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp new file mode 100644 index 0000000000..82e536a755 --- /dev/null +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -0,0 +1,104 @@ +/*************************************************************************/ +/* resource_importer_mp3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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. */ +/*************************************************************************/ + +#include "resource_importer_mp3.h" + +#include "core/io/resource_saver.h" +#include "core/os/file_access.h" +#include "scene/resources/texture.h" + +String ResourceImporterMP3::get_importer_name() const { + return "mp3"; +} + +String ResourceImporterMP3::get_visible_name() const { + return "MP3"; +} + +void ResourceImporterMP3::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("mp3"); +} + +String ResourceImporterMP3::get_save_extension() const { + return "mp3str"; +} + +String ResourceImporterMP3::get_resource_type() const { + return "AudioStreamMP3"; +} + +bool ResourceImporterMP3::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { + return true; +} + +int ResourceImporterMP3::get_preset_count() const { + return 0; +} + +String ResourceImporterMP3::get_preset_name(int p_idx) const { + return String(); +} + +void ResourceImporterMP3::get_import_options(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)); +} + +Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<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"]; + + FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); + + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + + size_t len = f->get_len(); + + Vector<uint8_t> data; + data.resize(len); + uint8_t *w = data.ptrw(); + + f->get_buffer(w, len); + + memdelete(f); + + Ref<AudioStreamMP3> mp3_stream; + mp3_stream.instance(); + + mp3_stream->set_data(data); + ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT); + mp3_stream->set_loop(loop); + mp3_stream->set_loop_offset(loop_offset); + + return ResourceSaver::save(p_save_path + ".mp3str", mp3_stream); +} + +ResourceImporterMP3::ResourceImporterMP3() { +} diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h new file mode 100644 index 0000000000..c1e8315e21 --- /dev/null +++ b/modules/minimp3/resource_importer_mp3.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* resource_importer_mp3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 RESOURCE_IMPORTER_MP3_H +#define RESOURCE_IMPORTER_MP3_H + +#include "audio_stream_mp3.h" +#include "core/io/resource_importer.h" + +class ResourceImporterMP3 : public ResourceImporter { + GDCLASS(ResourceImporterMP3, ResourceImporter); + +public: + virtual String get_importer_name() const override; + virtual String get_visible_name() const override; + 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; + + virtual int get_preset_count() const override; + virtual String get_preset_name(int p_idx) const override; + + virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override; + + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; + + ResourceImporterMP3(); +}; + +#endif // RESOURCE_IMPORTER_MP3_H diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 6057004166..9b10bac2f0 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -97,6 +97,7 @@ def configure(env, env_mono): copy_mono_root = env["copy_mono_root"] mono_prefix = env["mono_prefix"] + mono_bcl = env["mono_bcl"] mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] @@ -397,7 +398,7 @@ def configure(env, env_mono): if tools_enabled: # Only supported for editor builds. - copy_mono_root_files(env, mono_root) + copy_mono_root_files(env, mono_root, mono_bcl) def make_template_dir(env, mono_root): @@ -430,7 +431,7 @@ def make_template_dir(env, mono_root): copy_mono_shared_libs(env, mono_root, template_mono_root_dir) -def copy_mono_root_files(env, mono_root): +def copy_mono_root_files(env, mono_root, mono_bcl): from glob import glob from shutil import copy from shutil import rmtree @@ -455,7 +456,7 @@ def copy_mono_root_files(env, mono_root): # Copy framework assemblies - mono_framework_dir = os.path.join(mono_root, "lib", "mono", "4.5") + mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5") mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades") editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5") diff --git a/modules/mono/config.py b/modules/mono/config.py index c4a6b408e6..4c851a2989 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -27,6 +27,14 @@ def configure(env): PathVariable.PathAccept, ) ) + envvars.Add( + PathVariable( + "mono_bcl", + "Path to a custom Mono BCL (Base Class Library) directory for the target platform", + "", + PathVariable.PathAccept, + ) + ) envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static)) envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True)) envvars.Add(BoolVariable("build_cil", "Build C# solutions", True)) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 9514cc9622..1a1639aac7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -2,6 +2,7 @@ using Godot; using System; using Godot.Collections; using GodotTools.Internals; +using JetBrains.Annotations; using File = GodotTools.Utils.File; using Path = System.IO.Path; @@ -26,6 +27,9 @@ namespace GodotTools.Build private TextEdit buildLog; private PopupMenu issuesListContextMenu; + private readonly object pendingBuildLogTextLock = new object(); + [NotNull] private string pendingBuildLogText = string.Empty; + [Signal] public event Action BuildStateChanged; public bool HasBuildExited { get; private set; } = false; @@ -240,16 +244,34 @@ namespace GodotTools.Build EmitSignal(nameof(BuildStateChanged)); } + private void UpdateBuildLogText() + { + lock (pendingBuildLogTextLock) + { + buildLog.Text += pendingBuildLogText; + pendingBuildLogText = string.Empty; + ScrollToLastNonEmptyLogLine(); + } + } + private void StdOutputReceived(string text) { - buildLog.Text += text + "\n"; - ScrollToLastNonEmptyLogLine(); + lock (pendingBuildLogTextLock) + { + if (pendingBuildLogText.Length == 0) + CallDeferred(nameof(UpdateBuildLogText)); + pendingBuildLogText += text + "\n"; + } } private void StdErrorReceived(string text) { - buildLog.Text += text + "\n"; - ScrollToLastNonEmptyLogLine(); + lock (pendingBuildLogTextLock) + { + if (pendingBuildLogText.Length == 0) + CallDeferred(nameof(UpdateBuildLogText)); + pendingBuildLogText += text + "\n"; + } } private void ScrollToLastNonEmptyLogLine() @@ -377,12 +399,14 @@ namespace GodotTools.Build BuildManager.BuildStarted += BuildStarted; BuildManager.BuildFinished += BuildFinished; // StdOutput/Error can be received from different threads, so we need to use CallDeferred - BuildManager.StdOutputReceived += line => CallDeferred(nameof(StdOutputReceived), line); - BuildManager.StdErrorReceived += line => CallDeferred(nameof(StdErrorReceived), line); + BuildManager.StdOutputReceived += StdOutputReceived; + BuildManager.StdErrorReceived += StdErrorReceived; } public void OnBeforeSerialize() { + // In case it didn't update yet. We don't want to have to serialize any pending output. + UpdateBuildLogText(); } public void OnAfterDeserialize() diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 6fefcd48a4..0cc1bb5f46 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -45,7 +45,7 @@ class BindingsGenerator { struct ConstantInterface { String name; String proxy_name; - int value; + int value = 0; const DocData::ConstantDoc *const_doc; ConstantInterface() {} @@ -75,7 +75,7 @@ class BindingsGenerator { struct PropertyInterface { StringName cname; String proxy_name; - int index; + int index = 0; StringName setter; StringName getter; @@ -480,7 +480,7 @@ class BindingsGenerator { String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq] String im_sig; // Signature for the C# method declaration String unique_sig; // Unique signature to avoid duplicates in containers - bool editor_only; + bool editor_only = false; InternalCall() {} diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 1a0d5743ae..b006eed69f 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -55,10 +55,10 @@ MonoAssemblyName *new_mono_assembly_name() { struct AssemblyRefInfo { String name; - uint16_t major; - uint16_t minor; - uint16_t build; - uint16_t revision; + uint16_t major = 0; + uint16_t minor = 0; + uint16_t build = 0; + uint16_t revision = 0; }; AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) { diff --git a/modules/mono/editor/script_class_parser.h b/modules/mono/editor/script_class_parser.h index 3c55fa07a7..deb6061191 100644 --- a/modules/mono/editor/script_class_parser.h +++ b/modules/mono/editor/script_class_parser.h @@ -45,22 +45,22 @@ public: }; String name; - Type type; + Type type = NAMESPACE_DECL; }; struct ClassDecl { String name; String namespace_; Vector<String> base; - bool nested; + bool nested = false; }; private: String code; - int idx; - int line; + int idx = 0; + int line = 0; String error_str; - bool error; + bool error = false; Variant value; Vector<ClassDecl> classes; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs index b33490f9cb..bd3bcb0c58 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs @@ -120,13 +120,13 @@ namespace Godot /// <param name="b">The destination quaternion.</param> /// <param name="preA">A quaternion before this quaternion.</param> /// <param name="postB">A quaternion after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t) + public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight) { - real_t t2 = (1.0f - t) * t * 2f; - Quat sp = Slerp(b, t); - Quat sq = preA.Slerpni(postB, t); + real_t t2 = (1.0f - weight) * weight * 2f; + Quat sp = Slerp(b, weight); + Quat sq = preA.Slerpni(postB, weight); return sp.Slerpni(sq, t2); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index d536b14eac..b74dd6f4f4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -194,15 +194,16 @@ namespace Godot /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> /// <param name="postB">A vector after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t) + public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) { Vector2 p0 = preA; Vector2 p1 = this; Vector2 p2 = b; Vector2 p3 = postB; + real_t t = weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 4a4a2a43cd..07f5b3c38e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -161,15 +161,16 @@ namespace Godot /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> /// <param name="postB">A vector after `b`.</param> - /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> - public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t) + public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) { Vector3 p0 = preA; Vector3 p1 = this; Vector3 p2 = b; Vector3 p3 = postB; + real_t t = weight; real_t t2 = t * t; real_t t3 = t2 * t; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 6575cbc1c8..b734f52e4e 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -290,7 +290,7 @@ bool GDMonoClass::has_public_parameterless_ctor() { return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC; } -GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) { MethodKey key = MethodKey(p_name, p_params_count); GDMonoMethod **match = methods.getptr(key); @@ -330,7 +330,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName return get_method(p_raw_method, p_name, params_count); } -GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) { +GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) { ERR_FAIL_NULL_V(p_raw_method, nullptr); MethodKey key = MethodKey(p_name, p_params_count); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 87db2fa033..b93dfec30a 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -59,13 +59,12 @@ class GDMonoClass { MethodKey() {} - MethodKey(const StringName &p_name, int p_params_count) { - name = p_name; - params_count = p_params_count; + MethodKey(const StringName &p_name, uint16_t p_params_count) : + name(p_name), params_count(p_params_count) { } StringName name; - int params_count; + uint16_t params_count = 0; }; StringName namespace_name; @@ -139,10 +138,10 @@ public: bool implements_interface(GDMonoClass *p_interface); bool has_public_parameterless_ctor(); - GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0); + GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0); GDMonoMethod *get_method(MonoMethod *p_raw_method); GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name); - GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); + GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count); GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); GDMonoField *get_field(const StringName &p_name); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 00a1e1e507..61d7f64a2a 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -46,29 +46,15 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) { } void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) { -#define SET_FROM_STRUCT(m_type) \ - { \ - GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, &from); \ - } - -#define SET_FROM_ARRAY(m_type) \ - { \ - MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \ - mono_field_set_value(p_object, mono_field, managed); \ - } - switch (type.type_encoding) { case MONO_TYPE_BOOLEAN: { MonoBoolean val = p_value.operator bool(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_CHAR: { int16_t val = p_value.operator unsigned short(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_I1: { int8_t val = p_value.operator signed char(); mono_field_set_value(p_object, mono_field, &val); @@ -85,7 +71,6 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ int64_t val = p_value.operator int64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_U1: { uint8_t val = p_value.operator unsigned char(); mono_field_set_value(p_object, mono_field, &val); @@ -102,93 +87,92 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ uint64_t val = p_value.operator uint64_t(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R4: { float val = p_value.operator float(); mono_field_set_value(p_object, mono_field, &val); } break; - case MONO_TYPE_R8: { double val = p_value.operator double(); mono_field_set_value(p_object, mono_field, &val); } break; - - case MONO_TYPE_STRING: { - if (p_value.get_type() == Variant::NIL) { - // Otherwise, Variant -> String would return the string "Null" - MonoString *mono_string = nullptr; - mono_field_set_value(p_object, mono_field, mono_string); - } else { - MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); - mono_field_set_value(p_object, mono_field, mono_string); - } - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *tclass = type.type_class; if (tclass == CACHED_CLASS(Vector2)) { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector2i)) { - SET_FROM_STRUCT(Vector2i); + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Rect2)) { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Rect2i)) { - SET_FROM_STRUCT(Rect2i); + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform2D)) { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector3)) { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Vector3i)) { - SET_FROM_STRUCT(Vector3i); + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Basis)) { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Quat)) { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Transform)) { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(AABB)) { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Color)) { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); break; } if (tclass == CACHED_CLASS(Plane)) { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); break; } @@ -267,118 +251,35 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'."); } break; - + case MONO_TYPE_STRING: { + if (p_value.get_type() == Variant::NIL) { + // Otherwise, Variant -> String would return the string "Null" + MonoString *mono_string = nullptr; + mono_field_set_value(p_object, mono_field, mono_string); + } else { + MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value); + mono_field_set_value(p_object, mono_field, mono_string); + } + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - SET_FROM_ARRAY(Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - SET_FROM_ARRAY(PackedByteArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - SET_FROM_ARRAY(PackedInt32Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - SET_FROM_ARRAY(PackedInt64Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - SET_FROM_ARRAY(PackedFloat32Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - SET_FROM_ARRAY(PackedFloat64Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - SET_FROM_ARRAY(PackedStringArray); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - SET_FROM_ARRAY(PackedVector2Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - SET_FROM_ARRAY(PackedVector3Array); - break; - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - SET_FROM_ARRAY(PackedColorArray); - break; - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class); + MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type."); } break; - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *()); + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - if (CACHED_CLASS(StringName) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - if (CACHED_CLASS(NodePath) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - if (CACHED_CLASS(RID) == type_class) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID()); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - type_class == CACHED_CLASS(System_Collections_ICollection) || - type_class == CACHED_CLASS(System_Collections_IEnumerable)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); + } break; + case MONO_TYPE_GENERICINST: { + MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class); + if (likely(managed != nullptr)) { mono_field_set_value(p_object, mono_field, managed); - break; } - - ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'."); } break; - case MONO_TYPE_OBJECT: { // Variant switch (p_value.get_type()) { @@ -404,43 +305,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, mono_string); } break; case Variant::VECTOR2: { - SET_FROM_STRUCT(Vector2); + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR2I: { - SET_FROM_STRUCT(Vector2i); + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::RECT2: { - SET_FROM_STRUCT(Rect2); + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::RECT2I: { - SET_FROM_STRUCT(Rect2i); + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR3: { - SET_FROM_STRUCT(Vector3); + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::VECTOR3I: { - SET_FROM_STRUCT(Vector3i); + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM2D: { - SET_FROM_STRUCT(Transform2D); + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::PLANE: { - SET_FROM_STRUCT(Plane); + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::QUAT: { - SET_FROM_STRUCT(Quat); + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::AABB: { - SET_FROM_STRUCT(AABB); + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::BASIS: { - SET_FROM_STRUCT(Basis); + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::TRANSFORM: { - SET_FROM_STRUCT(Transform); + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::COLOR: { - SET_FROM_STRUCT(Color); + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color()); + mono_field_set_value(p_object, mono_field, &from); } break; case Variant::STRING_NAME: { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName()); @@ -475,106 +389,49 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_BYTE_ARRAY: { - SET_FROM_ARRAY(PackedByteArray); + MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_INT32_ARRAY: { - SET_FROM_ARRAY(PackedInt32Array); + MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_INT64_ARRAY: { - SET_FROM_ARRAY(PackedInt64Array); + MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_FLOAT32_ARRAY: { - SET_FROM_ARRAY(PackedFloat32Array); + MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_FLOAT64_ARRAY: { - SET_FROM_ARRAY(PackedFloat64Array); + MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_STRING_ARRAY: { - SET_FROM_ARRAY(PackedStringArray); + MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_VECTOR2_ARRAY: { - SET_FROM_ARRAY(PackedVector2Array); + MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_VECTOR3_ARRAY: { - SET_FROM_ARRAY(PackedVector3Array); + MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array()); + mono_field_set_value(p_object, mono_field, managed); } break; case Variant::PACKED_COLOR_ARRAY: { - SET_FROM_ARRAY(PackedColorArray); + MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray()); + mono_field_set_value(p_object, mono_field, managed); } break; default: break; } } break; - - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(), - type.type_class, key_reftype, value_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(), - type.type_class, elem_reftype); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class); - mono_field_set_value(p_object, mono_field, managed); - break; - } - } break; - default: { ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + "."); } break; } - -#undef SET_FROM_ARRAY_AND_BREAK -#undef SET_FROM_STRUCT_AND_BREAK } MonoObject *GDMonoField::get_value(MonoObject *p_object) { diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index b8ee0204c4..7584e7ff0d 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -160,13 +160,13 @@ void GDMonoLog::initialize() { OS::Date date_now = OS::get_singleton()->get_date(); OS::Time time_now = OS::get_singleton()->get_time(); - String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d", + String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d", date_now.year, date_now.month, date_now.day, time_now.hour, time_now.min, time_now.sec); - log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id()); + log_file_name += str_format("_%d", OS::get_singleton()->get_process_id()); - log_file_name += ".txt"; + log_file_name += ".log"; log_file_path = logs_dir.plus_file(log_file_name); diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index eee880ba60..64b350f270 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -311,152 +311,590 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_ return false; } -MonoObject *variant_to_mono_object(const Variant *p_var) { - ManagedType type; +MonoString *variant_to_mono_string(const Variant &p_var) { + if (p_var.get_type() == Variant::NIL) { + return nullptr; // Otherwise, Variant -> String would return the string "Null" + } + return mono_string_from_godot(p_var.operator String()); +} + +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) { + MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type()); + + if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { + return Array_to_mono_array(p_var.operator Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { + return PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { + return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { + return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(float)) { + return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(double)) { + return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(String)) { + return PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { + return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { + return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); + } + + if (array_type->eklass == CACHED_CLASS_RAW(Color)) { + return PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); + } + + if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) { + return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + + GDMonoClass::get_full_name(array_type->eklass) + "'."); +} + +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) { + // GodotObject + if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) { + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + } + + if (CACHED_CLASS(StringName) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator StringName()); + } + + if (CACHED_CLASS(NodePath) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + } - type.type_encoding = MONO_TYPE_OBJECT; - // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding + if (CACHED_CLASS(RID) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + } + + // Godot.Collections.Dictionary or IDictionary + if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + } - return variant_to_mono_object(p_var, type); + // Godot.Collections.Array or ICollection or IEnumerable + if (CACHED_CLASS(Array) == p_type_class || + CACHED_CLASS(System_Collections_ICollection) == p_type_class || + CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + + p_type_class->get_full_name() + "'."); } -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) { + MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type()); + + // Godot.Collections.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class); + } + + // Godot.Collections.Array<T> + if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { + return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class); + } + + // System.Collections.Generic.Dictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { + MonoReflectionType *key_reftype = nullptr; + MonoReflectionType *value_reftype = nullptr; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype); + } + + // System.Collections.Generic.List<T> + if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { + MonoReflectionType *elem_reftype = nullptr; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype); + } + + // IDictionary<TKey, TValue> + if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { + MonoReflectionType *key_reftype; + MonoReflectionType *value_reftype; + GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); + GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class); + } + + // ICollection<T> or IEnumerable<T> + if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { + MonoReflectionType *elem_reftype; + GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); + GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); + + return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + + p_type_class->get_full_name() + "'."); +} + +MonoObject *variant_to_mono_object(const Variant &p_var) { + // Variant + switch (p_var.get_type()) { + case Variant::BOOL: { + MonoBoolean val = p_var.operator bool(); + return BOX_BOOLEAN(val); + } + case Variant::INT: { + int64_t val = p_var.operator int64_t(); + return BOX_INT64(val); + } + case Variant::FLOAT: { +#ifdef REAL_T_IS_DOUBLE + double val = p_var.operator double(); + return BOX_DOUBLE(val); +#else + float val = p_var.operator float(); + return BOX_FLOAT(val); +#endif + } + case Variant::STRING: + return (MonoObject *)mono_string_from_godot(p_var.operator String()); + case Variant::VECTOR2: { + GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); + } + case Variant::VECTOR2I: { + GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); + } + case Variant::RECT2: { + GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); + } + case Variant::RECT2I: { + GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); + } + case Variant::VECTOR3: { + GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); + } + case Variant::VECTOR3I: { + GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); + } + case Variant::TRANSFORM2D: { + GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); + } + case Variant::PLANE: { + GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); + } + case Variant::QUAT: { + GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); + } + case Variant::AABB: { + GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); + } + case Variant::BASIS: { + GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); + } + case Variant::TRANSFORM: { + GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); + } + case Variant::COLOR: { + GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); + } + case Variant::STRING_NAME: + return GDMonoUtils::create_managed_from(p_var.operator StringName()); + case Variant::NODE_PATH: + return GDMonoUtils::create_managed_from(p_var.operator NodePath()); + case Variant::RID: + return GDMonoUtils::create_managed_from(p_var.operator ::RID()); + case Variant::OBJECT: + return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *()); + case Variant::CALLABLE: { + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); + } + case Variant::SIGNAL: { + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); + } + case Variant::DICTIONARY: + return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary)); + case Variant::ARRAY: + return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array)); + case Variant::PACKED_BYTE_ARRAY: + return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray()); + case Variant::PACKED_INT32_ARRAY: + return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array()); + case Variant::PACKED_INT64_ARRAY: + return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array()); + case Variant::PACKED_FLOAT32_ARRAY: + return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array()); + case Variant::PACKED_FLOAT64_ARRAY: + return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array()); + case Variant::PACKED_STRING_ARRAY: + return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray()); + case Variant::PACKED_VECTOR2_ARRAY: + return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array()); + case Variant::PACKED_VECTOR3_ARRAY: + return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array()); + case Variant::PACKED_COLOR_ARRAY: + return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray()); + default: + return nullptr; + } +} + +size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { + // This method prints no errors for unsupported types. It's called on all methods, not only + // those that end up being invoked with Variant parameters. + + // For MonoObject* we return 0, as it doesn't need to be stored. + constexpr size_t zero_for_mono_object = 0; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + case MONO_TYPE_R4: + return sizeof(float); + case MONO_TYPE_R8: + return sizeof(double); + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; + +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + return sizeof(M_##m_struct); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + RETURN_CHECK_FOR_STRUCT(Callable); + RETURN_CHECK_FOR_STRUCT(SignalInfo); + +#undef RETURN_CHECK_FOR_STRUCT + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: + return sizeof(MonoBoolean); + case MONO_TYPE_CHAR: + return sizeof(uint16_t); + case MONO_TYPE_I1: + return sizeof(int8_t); + case MONO_TYPE_I2: + return sizeof(int16_t); + case MONO_TYPE_I4: + return sizeof(int32_t); + case MONO_TYPE_I8: + return sizeof(int64_t); + case MONO_TYPE_U1: + return sizeof(uint8_t); + case MONO_TYPE_U2: + return sizeof(uint16_t); + case MONO_TYPE_U4: + return sizeof(uint32_t); + case MONO_TYPE_U8: + return sizeof(uint64_t); + default: { + // Enum with unsupported base type. We return nullptr MonoObject* on error. + return zero_for_mono_object; + } + } + } + + // Enum with unsupported value type. We return nullptr MonoObject* on error. + } break; + case MONO_TYPE_STRING: + return zero_for_mono_object; + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_GENERICINST: + return zero_for_mono_object; + case MONO_TYPE_OBJECT: + return zero_for_mono_object; + } + + // Unsupported type encoding. We return nullptr MonoObject* on error. + return zero_for_mono_object; +} + +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { +#define RETURN_TYPE_VAL(m_type, m_val) \ + *reinterpret_cast<m_type *>(r_buffer) = m_val; \ + r_offset += sizeof(m_type); \ + return r_buffer; + + switch (p_type.type_encoding) { + case MONO_TYPE_BOOLEAN: + RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool()); + case MONO_TYPE_CHAR: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_I1: + RETURN_TYPE_VAL(int8_t, p_var.operator signed char()); + case MONO_TYPE_I2: + RETURN_TYPE_VAL(int16_t, p_var.operator signed short()); + case MONO_TYPE_I4: + RETURN_TYPE_VAL(int32_t, p_var.operator signed int()); + case MONO_TYPE_I8: + RETURN_TYPE_VAL(int64_t, p_var.operator int64_t()); + case MONO_TYPE_U1: + RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char()); + case MONO_TYPE_U2: + RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short()); + case MONO_TYPE_U4: + RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int()); + case MONO_TYPE_U8: + RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t()); + case MONO_TYPE_R4: + RETURN_TYPE_VAL(float, p_var.operator float()); + case MONO_TYPE_R8: + RETURN_TYPE_VAL(double, p_var.operator double()); + case MONO_TYPE_VALUETYPE: { + GDMonoClass *vtclass = p_type.type_class; + +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + RETURN_TYPE_VAL(M_##m_struct, from); \ + } + + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT + + if (vtclass == CACHED_CLASS(Callable)) { + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); + RETURN_TYPE_VAL(M_Callable, from); + } + + if (vtclass == CACHED_CLASS(SignalInfo)) { + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); + RETURN_TYPE_VAL(M_SignalInfo, from); + } + + if (mono_class_is_enum(vtclass->get_mono_ptr())) { + MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr()); + switch (mono_type_get_type(enum_basetype)) { + case MONO_TYPE_BOOLEAN: { + MonoBoolean val = p_var.operator bool(); + RETURN_TYPE_VAL(MonoBoolean, val); + } + case MONO_TYPE_CHAR: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_I1: { + int8_t val = p_var.operator signed char(); + RETURN_TYPE_VAL(int8_t, val); + } + case MONO_TYPE_I2: { + int16_t val = p_var.operator signed short(); + RETURN_TYPE_VAL(int16_t, val); + } + case MONO_TYPE_I4: { + int32_t val = p_var.operator signed int(); + RETURN_TYPE_VAL(int32_t, val); + } + case MONO_TYPE_I8: { + int64_t val = p_var.operator int64_t(); + RETURN_TYPE_VAL(int64_t, val); + } + case MONO_TYPE_U1: { + uint8_t val = p_var.operator unsigned char(); + RETURN_TYPE_VAL(uint8_t, val); + } + case MONO_TYPE_U2: { + uint16_t val = p_var.operator unsigned short(); + RETURN_TYPE_VAL(uint16_t, val); + } + case MONO_TYPE_U4: { + uint32_t val = p_var.operator unsigned int(); + RETURN_TYPE_VAL(uint32_t, val); + } + case MONO_TYPE_U8: { + uint64_t val = p_var.operator uint64_t(); + RETURN_TYPE_VAL(uint64_t, val); + } + default: { + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'."); + } + } + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + + p_type.type_class->get_full_name() + "'."); + } break; +#undef RETURN_TYPE_VAL + case MONO_TYPE_STRING: + return variant_to_mono_string(p_var); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); + } + + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + + itos(p_type.type_encoding) + "."); +} + +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); + MonoBoolean val = p_var.operator bool(); return BOX_BOOLEAN(val); } - case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_UINT16(val); } - case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); + int8_t val = p_var.operator signed char(); return BOX_INT8(val); } case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); + int16_t val = p_var.operator signed short(); return BOX_INT16(val); } case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + int32_t val = p_var.operator signed int(); return BOX_INT32(val); } case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); + int64_t val = p_var.operator int64_t(); return BOX_INT64(val); } - case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); + uint8_t val = p_var.operator unsigned char(); return BOX_UINT8(val); } case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_UINT16(val); } case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); + uint32_t val = p_var.operator unsigned int(); return BOX_UINT32(val); } case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); + uint64_t val = p_var.operator uint64_t(); return BOX_UINT64(val); } - case MONO_TYPE_R4: { - float val = p_var->operator float(); + float val = p_var.operator float(); return BOX_FLOAT(val); } case MONO_TYPE_R8: { - double val = p_var->operator double(); + double val = p_var.operator double(); return BOX_DOUBLE(val); } - - case MONO_TYPE_STRING: { - if (p_var->get_type() == Variant::NIL) { - return nullptr; // Otherwise, Variant -> String would return the string "Null" - } - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; - if (vtclass == CACHED_CLASS(Vector2)) { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - - if (vtclass == CACHED_CLASS(Vector2i)) { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); - } - - if (vtclass == CACHED_CLASS(Rect2)) { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - - if (vtclass == CACHED_CLASS(Rect2i)) { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); - } - - if (vtclass == CACHED_CLASS(Transform2D)) { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - - if (vtclass == CACHED_CLASS(Vector3)) { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - - if (vtclass == CACHED_CLASS(Vector3i)) { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); - } - - if (vtclass == CACHED_CLASS(Basis)) { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - - if (vtclass == CACHED_CLASS(Quat)) { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } - - if (vtclass == CACHED_CLASS(Transform)) { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } - - if (vtclass == CACHED_CLASS(AABB)) { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - - if (vtclass == CACHED_CLASS(Color)) { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } +#define RETURN_CHECK_FOR_STRUCT(m_struct) \ + if (vtclass == CACHED_CLASS(m_struct)) { \ + GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \ + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \ + } - if (vtclass == CACHED_CLASS(Plane)) { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } + RETURN_CHECK_FOR_STRUCT(Vector2); + RETURN_CHECK_FOR_STRUCT(Vector2i); + RETURN_CHECK_FOR_STRUCT(Rect2); + RETURN_CHECK_FOR_STRUCT(Rect2i); + RETURN_CHECK_FOR_STRUCT(Transform2D); + RETURN_CHECK_FOR_STRUCT(Vector3); + RETURN_CHECK_FOR_STRUCT(Vector3i); + RETURN_CHECK_FOR_STRUCT(Basis); + RETURN_CHECK_FOR_STRUCT(Quat); + RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(AABB); + RETURN_CHECK_FOR_STRUCT(Color); + RETURN_CHECK_FOR_STRUCT(Plane); + +#undef RETURN_CHECK_FOR_STRUCT if (vtclass == CACHED_CLASS(Callable)) { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable()); + GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); } if (vtclass == CACHED_CLASS(SignalInfo)) { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal()); + GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); } @@ -465,316 +903,84 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype); switch (mono_type_get_type(enum_basetype)) { case MONO_TYPE_BOOLEAN: { - MonoBoolean val = p_var->operator bool(); + MonoBoolean val = p_var.operator bool(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_CHAR: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I1: { - int8_t val = p_var->operator signed char(); + int8_t val = p_var.operator signed char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I2: { - int16_t val = p_var->operator signed short(); + int16_t val = p_var.operator signed short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I4: { - int32_t val = p_var->operator signed int(); + int32_t val = p_var.operator signed int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_I8: { - int64_t val = p_var->operator int64_t(); + int64_t val = p_var.operator int64_t(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U1: { - uint8_t val = p_var->operator unsigned char(); + uint8_t val = p_var.operator unsigned char(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U2: { - uint16_t val = p_var->operator unsigned short(); + uint16_t val = p_var.operator unsigned short(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U4: { - uint32_t val = p_var->operator unsigned int(); + uint32_t val = p_var.operator unsigned int(); return BOX_ENUM(enum_baseclass, val); } case MONO_TYPE_U8: { - uint64_t val = p_var->operator uint64_t(); + uint64_t val = p_var.operator uint64_t(); return BOX_ENUM(enum_baseclass, val); } default: { - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + + GDMonoClass::get_full_name(enum_baseclass) + "'."); } } } - } break; - - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); - - if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) { - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) { - return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) { - return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) { - return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(float)) { - return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(double)) { - return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(String)) { - return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) { - return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) { - return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array()); - } - - if (array_type->eklass == CACHED_CLASS_RAW(Color)) { - return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); - } - - GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); - if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { - return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class); - } - - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type."); - } break; - - case MONO_TYPE_CLASS: { - GDMonoClass *type_class = p_type.type_class; - - // GodotObject - if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - } - - if (CACHED_CLASS(StringName) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator StringName()); - } - - if (CACHED_CLASS(NodePath) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - } - - if (CACHED_CLASS(RID) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator ::RID()); - } - - // Godot.Collections.Dictionary or IDictionary - if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - } - - // Godot.Collections.Array or ICollection or IEnumerable - if (CACHED_CLASS(Array) == type_class || - CACHED_CLASS(System_Collections_ICollection) == type_class || - CACHED_CLASS(System_Collections_IEnumerable) == type_class) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - } - } break; - case MONO_TYPE_OBJECT: { - // Variant - switch (p_var->get_type()) { - case Variant::BOOL: { - MonoBoolean val = p_var->operator bool(); - return BOX_BOOLEAN(val); - } - case Variant::INT: { - int64_t val = p_var->operator int64_t(); - return BOX_INT64(val); - } - case Variant::FLOAT: { -#ifdef REAL_T_IS_DOUBLE - double val = p_var->operator double(); - return BOX_DOUBLE(val); -#else - float val = p_var->operator float(); - return BOX_FLOAT(val); -#endif - } - case Variant::STRING: - return (MonoObject *)mono_string_from_godot(p_var->operator String()); - case Variant::VECTOR2: { - GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from); - } - case Variant::VECTOR2I: { - GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from); - } - case Variant::RECT2: { - GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from); - } - case Variant::RECT2I: { - GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from); - } - case Variant::VECTOR3: { - GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from); - } - case Variant::VECTOR3I: { - GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from); - } - case Variant::TRANSFORM2D: { - GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from); - } - case Variant::PLANE: { - GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); - } - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); - } - case Variant::AABB: { - GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from); - } - case Variant::BASIS: { - GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); - } - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); - } - case Variant::COLOR: { - GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from); - } - case Variant::STRING_NAME: - return GDMonoUtils::create_managed_from(p_var->operator StringName()); - case Variant::NODE_PATH: - return GDMonoUtils::create_managed_from(p_var->operator NodePath()); - case Variant::RID: - return GDMonoUtils::create_managed_from(p_var->operator ::RID()); - case Variant::OBJECT: - return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); - case Variant::CALLABLE: { - GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from); - } - case Variant::SIGNAL: { - GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from); - } - case Variant::DICTIONARY: - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); - case Variant::ARRAY: - return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); - case Variant::PACKED_BYTE_ARRAY: - return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray()); - case Variant::PACKED_INT32_ARRAY: - return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array()); - case Variant::PACKED_INT64_ARRAY: - return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array()); - case Variant::PACKED_FLOAT32_ARRAY: - return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array()); - case Variant::PACKED_FLOAT64_ARRAY: - return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array()); - case Variant::PACKED_STRING_ARRAY: - return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray()); - case Variant::PACKED_VECTOR2_ARRAY: - return (MonoObject *)PackedVector2Array_to_mono_array(p_var->operator PackedVector2Array()); - case Variant::PACKED_VECTOR3_ARRAY: - return (MonoObject *)PackedVector3Array_to_mono_array(p_var->operator PackedVector3Array()); - case Variant::PACKED_COLOR_ARRAY: - return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray()); - default: - return nullptr; - } - break; - case MONO_TYPE_GENERICINST: { - MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); - - // Godot.Collections.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); - } - - // Godot.Collections.Array<T> - if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) { - return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); - } - - // System.Collections.Generic.Dictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) { - MonoReflectionType *key_reftype = nullptr; - MonoReflectionType *value_reftype = nullptr; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype); - } - - // System.Collections.Generic.List<T> - if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) { - MonoReflectionType *elem_reftype = nullptr; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype); - } - - // IDictionary<TKey, TValue> - if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) { - MonoReflectionType *key_reftype; - MonoReflectionType *value_reftype; - GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype); - GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class); - } - // ICollection<T> or IEnumerable<T> - if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) { - MonoReflectionType *elem_reftype; - GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype); - GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype); - - return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class); - } - } break; + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + + p_type.type_class->get_full_name() + "'."); } break; + case MONO_TYPE_STRING: + return (MonoObject *)variant_to_mono_string(p_var); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class); + case MONO_TYPE_CLASS: + return variant_to_mono_object_of_class(p_var, p_type.type_class); + case MONO_TYPE_GENERICINST: + return variant_to_mono_object_of_genericinst(p_var, p_type.type_class); + case MONO_TYPE_OBJECT: + return variant_to_mono_object(p_var); } - ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" + - p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + "."); + ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + + itos(p_type.type_encoding) + "."); } Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) { ERR_FAIL_COND_V(!p_type.type_class, Variant()); +#ifdef DEBUG_ENABLED + CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known."); +#endif + switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: return (bool)unbox<MonoBoolean>(p_obj); - case MONO_TYPE_CHAR: return unbox<uint16_t>(p_obj); - case MONO_TYPE_I1: return unbox<int8_t>(p_obj); case MONO_TYPE_I2: @@ -783,7 +989,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<int32_t>(p_obj); case MONO_TYPE_I8: return unbox<int64_t>(p_obj); - case MONO_TYPE_U1: return unbox<uint8_t>(p_obj); case MONO_TYPE_U2: @@ -792,19 +997,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<uint32_t>(p_obj); case MONO_TYPE_U8: return unbox<uint64_t>(p_obj); - case MONO_TYPE_R4: return unbox<float>(p_obj); case MONO_TYPE_R8: return unbox<double>(p_obj); - - case MONO_TYPE_STRING: { - if (p_obj == nullptr) { - return Variant(); // NIL - } - return mono_string_to_godot_not_null((MonoString *)p_obj); - } break; - case MONO_TYPE_VALUETYPE: { GDMonoClass *vtclass = p_type.type_class; @@ -872,7 +1068,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return unbox<int32_t>(p_obj); } } break; - + case MONO_TYPE_STRING: { + if (p_obj == nullptr) { + return Variant(); // NIL + } + return mono_string_to_godot_not_null((MonoString *)p_obj); + } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); @@ -928,7 +1129,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return Variant(); } } break; - case MONO_TYPE_CLASS: { GDMonoClass *type_class = p_type.type_class; @@ -973,7 +1173,6 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return ptr ? Variant(*ptr) : Variant(); } } break; - case MONO_TYPE_GENERICINST: { MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); @@ -1052,7 +1251,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj)); Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type); - if (var.get_type() == Variant::NIL && p_obj != nullptr) { + if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. MonoException *exc = nullptr; MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); @@ -1115,9 +1314,10 @@ Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] } MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) { - GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class; + MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype); + MonoClass *elem_class = mono_class_from_mono_type(elem_type); - String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)"; + String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)"; GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true); CRASH_COND(ctor == nullptr); @@ -1156,9 +1356,9 @@ MonoArray *Array_to_mono_array(const Array &p_array) { return ret; } -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) { +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) { int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length); + MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length); for (int i = 0; i < length; i++) { MonoObject *boxed = variant_to_mono_object(p_array[i]); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index d1d5f1f202..6d8227f8b4 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -90,15 +90,40 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { // Variant -MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type); -MonoObject *variant_to_mono_object(const Variant *p_var); - -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) { - return variant_to_mono_object(&p_var); +size_t variant_get_managed_unboxed_size(const ManagedType &p_type); +void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset); +MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type); + +MonoObject *variant_to_mono_object(const Variant &p_var); +MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class); +MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class); +MonoString *variant_to_mono_string(const Variant &p_var); + +// These overloads were added to avoid passing a `const Variant *` to the `const Variant &` +// parameter. That would result in the `Variant(bool)` copy constructor being called as +// pointers are implicitly converted to bool. Implicit conversions are f-ing evil. + +_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) { + return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset); } - -_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { - return variant_to_mono_object(&p_var, p_type); +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { + return variant_to_mono_object(*p_var, p_type); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) { + return variant_to_mono_object(*p_var); +} +_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_array(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_class(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) { + return variant_to_mono_object_of_genericinst(*p_var, p_type_class); +} +_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) { + return variant_to_mono_string(*p_var); } Variant mono_object_to_variant(MonoObject *p_obj); @@ -120,7 +145,7 @@ Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, Mono // Array MonoArray *Array_to_mono_array(const Array &p_array); -MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class); +MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class); Array mono_array_to_Array(MonoArray *p_array); // PackedInt32Array diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 04f3b25a70..1d87726234 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -75,6 +75,10 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) { // clear the cache method_info_fetched = false; method_info = MethodInfo(); + + for (int i = 0; i < params_count; i++) { + params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]); + } } GDMonoClass *GDMonoMethod::get_enclosing_class() const { @@ -107,14 +111,15 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoObject *ret; if (params_count > 0) { - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), params_count); + void **params = (void **)alloca(params_count * sizeof(void *)); + uint8_t *buffer = (uint8_t *)alloca(params_buffer_size); + unsigned int offset = 0; for (int i = 0; i < params_count; i++) { - MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]); - mono_array_setref(params, i, boxed_param); + params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset); } - ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc); + ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc); } else { ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc); } @@ -279,16 +284,8 @@ const MethodInfo &GDMonoMethod::get_method_info() { return method_info; } -GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) { - name = p_name; - - mono_method = p_method; - - method_info_fetched = false; - - attrs_fetched = false; - attributes = nullptr; - +GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) : + name(p_name), mono_method(p_method) { _update_signature(); } diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index f78f57dca0..115bd998fa 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -38,15 +38,16 @@ class GDMonoMethod : public IMonoClassMember { StringName name; - int params_count; + uint16_t params_count; + unsigned int params_buffer_size = 0; ManagedType return_type; Vector<ManagedType> param_types; - bool method_info_fetched; + bool method_info_fetched = false; MethodInfo method_info; - bool attrs_fetched; - MonoCustomAttrInfo *attributes; + bool attrs_fetched = false; + MonoCustomAttrInfo *attributes = nullptr; void _update_signature(); void _update_signature(MonoMethodSignature *p_method_sig); @@ -72,7 +73,7 @@ public: _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; } - _FORCE_INLINE_ int get_parameters_count() const { return params_count; } + _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; } _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; } MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const; diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index bc3be97102..1027c08a4a 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -149,10 +149,9 @@ bool GDMonoProperty::has_setter() { void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) { MonoMethod *prop_method = mono_property_get_set_method(mono_property); - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); - mono_array_setref(params, 0, p_value); + void *params[1] = { p_value }; MonoException *exc = nullptr; - GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc); + GDMonoUtils::runtime_invoke(prop_method, p_object, params, &exc); if (exc) { if (r_exc) { *r_exc = exc; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 97fc4c57f9..05fd57255c 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -480,6 +480,7 @@ void set_pending_exception(MonoException *p_exc) { #else if (get_runtime_invoke_count() == 0) { debug_unhandled_exception(p_exc); + return; } if (!mono_runtime_set_pending_exception(p_exc, false)) { @@ -498,13 +499,6 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M return ret; } -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc); - GD_MONO_END_RUNTIME_INVOKE; - return ret; -} - MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) { GD_MONO_BEGIN_RUNTIME_INVOKE; MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 71c131f77c..faa3d24eeb 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -135,7 +135,6 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() { } MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc); -MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc); MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc); diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index bd67b03c8e..f220abfb4c 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -48,18 +48,10 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa } bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { + // Only called if both instances are of type SignalAwaiterCallable. Static cast is safe. const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a); const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b); - - if (a->target_id != b->target_id) { - return false; - } - - if (a->signal != b->signal) { - return false; - } - - return true; + return a->awaiter_handle.handle == b->awaiter_handle.handle; } bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { @@ -109,11 +101,15 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va "Resumed after await, but class instance is gone."); #endif - MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount); + MonoArray *signal_args = nullptr; - for (int i = 0; i < p_argcount; i++) { - MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]); - mono_array_setref(signal_args, i, boxed); + if (p_argcount > 0) { + signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount); + + for (int i = 0; i < p_argcount; i++) { + MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]); + mono_array_setref(signal_args, i, boxed); + } } MonoObject *awaiter = awaiter_handle.get_target(); diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp new file mode 100644 index 0000000000..6695a539d0 --- /dev/null +++ b/modules/pvr/image_compress_pvrtc.cpp @@ -0,0 +1,84 @@ +/*************************************************************************/ +/* image_compress_pvrtc.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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. */ +/*************************************************************************/ + +#include "image_compress_pvrtc.h" + +#include "core/io/image.h" +#include "core/object/reference.h" + +#include <PvrTcEncoder.h> +#include <RgbaBitmap.h> + +static void _compress_pvrtc1_4bpp(Image *p_img) { + Ref<Image> img = p_img->duplicate(); + + bool make_mipmaps = false; + if (!img->is_size_po2() || img->get_width() != img->get_height()) { + make_mipmaps = img->has_mipmaps(); + img->resize_to_po2(true); + } + img->convert(Image::FORMAT_RGBA8); + if (!img->has_mipmaps() && make_mipmaps) { + img->generate_mipmaps(); + } + + bool use_alpha = img->detect_alpha(); + + Ref<Image> new_img; + new_img.instance(); + new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4); + + Vector<uint8_t> data = new_img->get_data(); + { + uint8_t *wr = data.ptrw(); + const uint8_t *r = img->get_data().ptr(); + + for (int i = 0; i <= new_img->get_mipmap_count(); i++) { + int ofs, size, w, h; + img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); + Javelin::RgbaBitmap bm(w, h); + void *dst = (void *)bm.GetData(); + copymem(dst, &r[ofs], size); + Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); + for (int j = 0; j < size / 4; j++) { + // Red and blue colors are swapped. + SWAP(dp[j].r, dp[j].b); + } + new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); + Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); + } + } + + p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); +} + +void _register_pvrtc_compress_func() { + Image::_image_compress_pvrtc1_4bpp_func = _compress_pvrtc1_4bpp; +} diff --git a/modules/pvr/image_compress_pvrtc.h b/modules/pvr/image_compress_pvrtc.h new file mode 100644 index 0000000000..fde65f4bbe --- /dev/null +++ b/modules/pvr/image_compress_pvrtc.h @@ -0,0 +1,36 @@ +/*************************************************************************/ +/* image_compress_pvrtc.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 IMAGE_COMPRESS_PVRTC_H +#define IMAGE_COMPRESS_PVRTC_H + +void _register_pvrtc_compress_func(); + +#endif // IMAGE_COMPRESS_PVRTC_H diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp index 1eb697bba3..9bfc334d76 100644 --- a/modules/pvr/register_types.cpp +++ b/modules/pvr/register_types.cpp @@ -30,6 +30,7 @@ #include "register_types.h" +#include "image_compress_pvrtc.h" #include "texture_loader_pvr.h" static Ref<ResourceFormatPVR> resource_loader_pvr; @@ -37,6 +38,8 @@ static Ref<ResourceFormatPVR> resource_loader_pvr; void register_pvr_types() { resource_loader_pvr.instance(); ResourceLoader::add_resource_format_loader(resource_loader_pvr); + + _register_pvrtc_compress_func(); } void unregister_pvr_types() { diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 0923714387..c9cbb1935a 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -29,11 +29,8 @@ /*************************************************************************/ #include "texture_loader_pvr.h" -#include "PvrTcEncoder.h" -#include "RgbaBitmap.h" + #include "core/os/file_access.h" -#include <string.h> -#include <new> static void _pvrtc_decompress(Image *p_img); @@ -111,11 +108,11 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, switch (flags & 0xFF) { case 0x18: case 0xC: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC2A : Image::FORMAT_PVRTC2; + format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_2A : Image::FORMAT_PVRTC1_2; break; case 0x19: case 0xD: - format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4; + format = (flags & PVR_HAS_ALPHA) ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4; break; case 0x16: format = Image::FORMAT_L8; @@ -183,53 +180,8 @@ String ResourceFormatPVR::get_resource_type(const String &p_path) const { return ""; } -static void _compress_pvrtc4(Image *p_img) { - Ref<Image> img = p_img->duplicate(); - - bool make_mipmaps = false; - if (!img->is_size_po2() || img->get_width() != img->get_height()) { - make_mipmaps = img->has_mipmaps(); - img->resize_to_po2(true); - } - img->convert(Image::FORMAT_RGBA8); - if (!img->has_mipmaps() && make_mipmaps) { - img->generate_mipmaps(); - } - - bool use_alpha = img->detect_alpha(); - - Ref<Image> new_img; - new_img.instance(); - new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC4A : Image::FORMAT_PVRTC4); - - Vector<uint8_t> data = new_img->get_data(); - { - uint8_t *wr = data.ptrw(); - const uint8_t *r = img->get_data().ptr(); - - for (int i = 0; i <= new_img->get_mipmap_count(); i++) { - int ofs, size, w, h; - img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::RgbaBitmap bm(w, h); - void *dst = (void *)bm.GetData(); - copymem(dst, &r[ofs], size); - Javelin::ColorRgba<unsigned char> *dp = bm.GetData(); - for (int j = 0; j < size / 4; j++) { - /* red and blue colors are swapped. */ - SWAP(dp[j].r, dp[j].b); - } - new_img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h); - Javelin::PvrTcEncoder::EncodeRgba4Bpp(&wr[ofs], bm); - } - } - - p_img->create(new_img->get_width(), new_img->get_height(), new_img->has_mipmaps(), new_img->get_format(), data); -} - ResourceFormatPVR::ResourceFormatPVR() { Image::_image_decompress_pvrtc = _pvrtc_decompress; - Image::_image_compress_pvrtc4_func = _compress_pvrtc4; - Image::_image_compress_pvrtc2_func = _compress_pvrtc4; } ///////////////////////////////////////////////////////// @@ -635,9 +587,9 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int } static void _pvrtc_decompress(Image *p_img) { - ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A); + ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC1_2 && p_img->get_format() != Image::FORMAT_PVRTC1_2A && p_img->get_format() != Image::FORMAT_PVRTC1_4 && p_img->get_format() != Image::FORMAT_PVRTC1_4A); - bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A); + bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC1_2 || p_img->get_format() == Image::FORMAT_PVRTC1_2A); Vector<uint8_t> data = p_img->get_data(); const uint8_t *r = data.ptr(); diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp index 10c3732fd7..b905b7dabb 100644 --- a/modules/text_server_adv/bitmap_font_adv.cpp +++ b/modules/text_server_adv/bitmap_font_adv.cpp @@ -175,8 +175,9 @@ static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_ return true; } -static hb_font_funcs_t *_hb_bmp_get_font_funcs() { - hb_font_funcs_t *funcs = hb_font_funcs_create(); +static hb_font_funcs_t *funcs = nullptr; +void hb_bmp_create_font_funcs() { + funcs = hb_font_funcs_create(); hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr); //hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr); @@ -194,12 +195,17 @@ static hb_font_funcs_t *_hb_bmp_get_font_funcs() { //hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr); hb_font_funcs_make_immutable(funcs); +} - return funcs; +void hb_bmp_free_font_funcs() { + if (funcs != nullptr) { + hb_font_funcs_destroy(funcs); + funcs = nullptr; + } } static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) { - hb_font_set_funcs(p_font, _hb_bmp_get_font_funcs(), _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy); + hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy); } hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) { @@ -384,7 +390,6 @@ Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_s chr.rect.position.y = c[2]; chr.rect.size.x = c[3]; chr.rect.size.y = c[4]; - chr.texture_idx = 0; if (c[7] < 0) { chr.advance.x = c[3]; } else { diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h index b2fe7f43af..cb1a726f76 100644 --- a/modules/text_server_adv/bitmap_font_adv.h +++ b/modules/text_server_adv/bitmap_font_adv.h @@ -33,6 +33,9 @@ #include "font_adv.h" +void hb_bmp_create_font_funcs(); +void hb_bmp_free_font_funcs(); + struct BitmapFontDataAdvanced : public FontDataAdvanced { _THREAD_SAFE_CLASS_ diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index 90e5cc8831..08c4ad2727 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -32,8 +32,7 @@ #include FT_STROKER_H #include FT_ADVANCES_H - -HashMap<String, Vector<uint8_t>> DynamicFontDataAdvanced::font_mem_cache; +#include FT_MULTIPLE_MASTERS_H DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) { ERR_FAIL_COND_V(!valid, nullptr); @@ -55,11 +54,10 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( if (E != nullptr) { fds = E->get(); } else { - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) { - if (font_mem_cache.has(font_path)) { - font_mem = font_mem_cache[font_path].ptr(); - font_mem_size = font_mem_cache[font_path].size(); + if (font_mem == nullptr && font_path != String()) { + if (!font_mem_cache.empty()) { + font_mem = font_mem_cache.ptr(); + font_mem_size = font_mem_cache.size(); } else { FileAccess *f = FileAccess::open(font_path, FileAccess::READ); if (!f) { @@ -67,11 +65,9 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( } size_t len = f->get_len(); - font_mem_cache[font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = font_mem_cache[font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font_mem = fontdata.ptr(); + font_mem_cache.resize(len); + f->get_buffer(font_mem_cache.ptrw(), len); + font_mem = font_mem_cache.ptr(); font_mem_size = len; f->close(); } @@ -79,27 +75,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( int error = 0; fds = memnew(DataAtSize); - if (font_mem == nullptr && font_path != String()) { - FileAccess *f = FileAccess::open(font_path, FileAccess::READ); - if (!f) { - memdelete(fds); - ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); - } - - memset(&fds->stream, 0, sizeof(FT_StreamRec)); - fds->stream.base = nullptr; - fds->stream.size = f->get_len(); - fds->stream.pos = 0; - fds->stream.descriptor.pointer = f; - fds->stream.read = _ft_stream_io; - fds->stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &fds->stream; - error = FT_Open_Face(library, &fargs, 0, &fds->face); - } else if (font_mem) { + if (font_mem) { memset(&fds->stream, 0, sizeof(FT_StreamRec)); fds->stream.base = (unsigned char *)font_mem; fds->stream.size = font_mem_size; @@ -159,33 +135,89 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size( memdelete(fds); ERR_FAIL_V_MSG(nullptr, "Error loading HB font."); } + if (p_outline_size != 0) { size_cache_outline[id] = fds; } else { size_cache[id] = fds; } - } + // Write variations. + if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var *amaster; + + FT_Get_MM_Var(fds->face, &amaster); + + Vector<hb_variation_t> hb_vars; + Vector<FT_Fixed> coords; + coords.resize(amaster->num_axis); + + FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw()); + + for (FT_UInt i = 0; i < amaster->num_axis; i++) { + hb_variation_t var; + + // Reset to default. + var.tag = amaster->axis[i].tag; + var.value = (double)amaster->axis[i].def / 65536.f; + coords.write[i] = amaster->axis[i].def; + + if (variations.has(var.tag)) { + var.value = variations[var.tag]; + coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum); + } + + hb_vars.push_back(var); + } + + FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw()); + hb_font_set_variations(fds->hb_handle, hb_vars.empty() ? nullptr : &hb_vars[0], hb_vars.size()); + + FT_Done_MM_Var(library, amaster); + } + } return fds; } -unsigned long DynamicFontDataAdvanced::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); +Dictionary DynamicFontDataAdvanced::get_variation_list() const { + _THREAD_SAFE_METHOD_ + DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size); + if (fds == nullptr) { + return Dictionary(); } - if (count == 0) { - return 0; + + Dictionary ret; + // Read variations. + if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var *amaster; + + FT_Get_MM_Var(fds->face, &amaster); + + for (FT_UInt i = 0; i < amaster->num_axis; i++) { + ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536); + } + + FT_Done_MM_Var(library, amaster); } + return ret; +} - return f->get_buffer(buffer, count); +void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) { + _THREAD_SAFE_METHOD_ + int32_t tag = TS->name_to_tag(p_name); + if (!variations.has(tag) || (variations[tag] != p_value)) { + variations[tag] = p_value; + clear_cache(); + } } -void DynamicFontDataAdvanced::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); +double DynamicFontDataAdvanced::get_variation(const String &p_name) const { + _THREAD_SAFE_METHOD_ + int32_t tag = TS->name_to_tag(p_name); + if (!variations.has(tag)) { + return 0.f; + } + return variations[tag]; } Dictionary DynamicFontDataAdvanced::get_feature_list() const { @@ -222,8 +254,6 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const { DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) { TexturePosition ret; ret.index = -1; - ret.x = 0; - ret.y = 0; int mw = p_width; int mh = p_height; diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h index 61cff3cde9..f9d6735c32 100644 --- a/modules/text_server_adv/dynamic_font_adv.h +++ b/modules/text_server_adv/dynamic_font_adv.h @@ -116,7 +116,9 @@ private: const uint8_t *font_mem = nullptr; int font_mem_size = 0; String font_path; - static HashMap<String, Vector<uint8_t>> font_mem_cache; + Vector<uint8_t> font_mem_cache; + + Map<int32_t, double> variations; float rect_margin = 1.f; int base_size = 16; @@ -128,9 +130,6 @@ private: Map<CacheID, DataAtSize *> size_cache; Map<CacheID, DataAtSize *> size_cache_outline; - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0); TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height); @@ -149,6 +148,10 @@ public: virtual float get_descent(int p_size) const override; virtual Dictionary get_feature_list() const override; + virtual Dictionary get_variation_list() const override; + + virtual void set_variation(const String &p_name, double p_value) override; + virtual double get_variation(const String &p_name) const override; virtual float get_underline_position(int p_size) const override; virtual float get_underline_thickness(int p_size) const override; diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h index 232d6d7d08..88b327f57b 100644 --- a/modules/text_server_adv/font_adv.h +++ b/modules/text_server_adv/font_adv.h @@ -50,6 +50,10 @@ struct FontDataAdvanced { virtual float get_descent(int p_size) const = 0; virtual Dictionary get_feature_list() const { return Dictionary(); }; + virtual Dictionary get_variation_list() const { return Dictionary(); }; + + virtual void set_variation(const String &p_name, double p_value){}; + virtual double get_variation(const String &p_name) const { return 0; }; virtual float get_underline_position(int p_size) const = 0; virtual float get_underline_thickness(int p_size) const = 0; diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index 8a2b2cced0..60a617c3a7 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -56,11 +56,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length int paren_sp = -1; int start_sp = paren_sp; UErrorCode err = U_ZERO_ERROR; + const char32_t *str = p_string.ptr(); do { script_code = USCRIPT_COMMON; for (script_start = script_end; script_end < p_length; script_end++) { - UChar32 ch = p_string[script_end]; + UChar32 ch = str[script_end]; UScriptCode sc = uscript_getScript(ch, &err); if (U_FAILURE(err)) { ERR_FAIL_MSG(u_errorName(err)); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index e391777eea..803004f93f 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { /*************************************************************************/ String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite"; -uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA; +uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE; bool TextServerAdvanced::has_feature(Feature p_feature) { return (interface_features & p_feature) == p_feature; @@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const { return fd->get_antialiased(); } +Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const { + _THREAD_SAFE_METHOD_ + const FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, Dictionary()); + return fd->get_variation_list(); +} + +void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) { + _THREAD_SAFE_METHOD_ + FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND(!fd); + fd->set_variation(p_name, p_value); +} + +double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const { + _THREAD_SAFE_METHOD_ + const FontDataAdvanced *fd = font_owner.getornull(p_font); + ERR_FAIL_COND_V(!fd, 0); + return fd->get_variation(p_name); +} + void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) { _THREAD_SAFE_METHOD_ FontDataAdvanced *fd = font_owner.getornull(p_font); @@ -1108,7 +1129,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->width = 0; sd->upos = 0; sd->uthk = 0; - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + + for (int i = 0; i < sd_size; i++) { Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { @@ -1128,8 +1151,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); @@ -1144,8 +1167,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); @@ -1160,19 +1183,19 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off)); sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off)); } else { - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance * gl.repeat; @@ -1248,6 +1271,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->utf16 = new_sd->text.utf16(); new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length())); + int sd_size = sd->glyphs.size(); + const Glyph *sd_glyphs = sd->glyphs.ptr(); + const FontDataAdvanced *fd = nullptr; + RID prev_rid = RID(); + for (int ov = 0; ov < sd->bidi_override.size(); ov++) { UErrorCode err = U_ZERO_ERROR; @@ -1280,21 +1308,23 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start); int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length); - for (int j = 0; j < sd->glyphs.size(); j++) { - if ((sd->glyphs[j].start >= bidi_run_start) && (sd->glyphs[j].end <= bidi_run_end)) { + for (int j = 0; j < sd_size; j++) { + if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) { // Copy glyphs. - Glyph gl = sd->glyphs[j]; + Glyph gl = sd_glyphs[j]; Variant key; + bool find_embedded = false; if (gl.count == 1) { for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (E->get().pos == gl.start) { + find_embedded = true; key = E->key(); new_sd->objects[key] = E->get(); break; } } } - if (key != Variant()) { + if (find_embedded) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; @@ -1303,8 +1333,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); @@ -1318,8 +1348,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); @@ -1327,23 +1357,26 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng } } } else { - const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid); + if (prev_rid != gl.font_rid) { + fd = font_owner.getornull(gl.font_rid); + prev_rid = gl.font_rid; + } if (fd != nullptr) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off)); new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off)); } else { - new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } new_sd->width += gl.advance * gl.repeat; @@ -1491,9 +1524,9 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - gl.advance = MAX(gl.advance + delta_width_per_space, 0.f); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f)); } else { - gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size)); } sd->width += (gl.advance - old_adv); } @@ -1529,8 +1562,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float delta = -1; } + Glyph *gl = sd->glyphs.ptrw(); + for (int i = start; i != end; i += delta) { - if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { + if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; @@ -1539,13 +1574,13 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float tab_index = 0; } } - float old_adv = sd->glyphs.write[i].advance; - sd->glyphs.write[i].advance = (tab_off - off); - sd->width += sd->glyphs.write[i].advance - old_adv; + float old_adv = gl[i].advance; + gl[i].advance = tab_off - off; + sd->width += gl[i].advance - old_adv; off = 0; continue; } - off += sd->glyphs[i].advance * sd->glyphs[i].repeat; + off += gl[i].advance * gl[i].repeat; } return 0.f; @@ -1565,8 +1600,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { const UChar *data = sd->utf16.ptr(); - Map<int, bool> breaks; - + HashMap<int, bool> breaks; UErrorCode err = U_ZERO_ERROR; for (int i = 0; i < sd->spans.size(); i++) { UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err); @@ -1598,40 +1632,47 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { sd->sort_valid = false; sd->glyphs_logical.clear(); + int sd_size = sd->glyphs.size(); + const char32_t *ch = sd->text.ptr(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); - for (int i = 0; i < sd->glyphs.size(); i++) { - if (sd->glyphs[i].count > 0) { - char32_t c = sd->text[sd->glyphs[i].start - sd->start]; + for (int i = 0; i < sd_size; i++) { + if (sd_glyphs[i].count > 0) { + char32_t c = ch[sd_glyphs[i].start - sd->start]; if (c == 0xfffc) { continue; } if (c == 0x0009 || c == 0x000b) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB; + sd_glyphs[i].flags |= GRAPHEME_IS_TAB; } if (breaks.has(sd->glyphs[i].start)) { if (breaks[sd->glyphs[i].start]) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } else { if (is_whitespace(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; - sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } else { TextServer::Glyph gl; - gl.start = sd->glyphs[i].start; - gl.end = sd->glyphs[i].end; + gl.start = sd_glyphs[i].start; + gl.end = sd_glyphs[i].end; gl.count = 1; - gl.repeat = 1; - gl.font_rid = sd->glyphs[i].font_rid; - gl.font_size = sd->glyphs[i].font_size; + gl.font_rid = sd_glyphs[i].font_rid; + gl.font_size = sd_glyphs[i].font_size; gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; - sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after - i += sd->glyphs[i].count; + sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after + + // Update write pointer and size. + sd_size = sd->glyphs.size(); + sd_glyphs = sd->glyphs.ptrw(); + + i += sd_glyphs[i].count; continue; } } } - i += (sd->glyphs[i].count - 1); + i += (sd_glyphs[i].count - 1); } } @@ -1767,9 +1808,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { sd->sort_valid = false; sd->glyphs_logical.clear(); + int sd_size = sd->glyphs.size(); if (jstops.size() > 0) { - for (int i = 0; i < sd->glyphs.size(); i++) { + for (int i = 0; i < sd_size; i++) { if (sd->glyphs[i].count > 0) { if (jstops.has(sd->glyphs[i].start)) { char32_t c = sd->text[sd->glyphs[i].start - sd->start]; @@ -1803,7 +1845,6 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { gl.start = sd->glyphs[i].start; gl.end = sd->glyphs[i].end; gl.count = 1; - gl.repeat = 1; gl.font_rid = sd->glyphs[i].font_rid; gl.font_size = sd->glyphs[i].font_size; gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL; @@ -1838,8 +1879,6 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced // Process glyphs. TextServer::Glyph gl; - gl.start = -1; - gl.end = -1; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { gl.flags |= TextServer::GRAPHEME_IS_RTL; @@ -1850,15 +1889,15 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced if (glyph_count > 0) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)); + gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size))); } else { - gl.advance = -glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)); + gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size))); } gl.count = 1; gl.index = glyph_info[0].codepoint; - gl.x_off = glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)); - gl.y_off = -glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)); + gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size))); + gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size))); if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) { gl.flags |= GRAPHEME_IS_VALID; @@ -1873,8 +1912,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star fd = font_owner.getornull(p_fonts[p_fb_index]); } + int fs = p_sd->spans[p_span].font_size; if (fd == nullptr) { - // Add fallback glyohs + // Add fallback glyphs for (int i = p_start; i < p_end; i++) { if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) { TextServer::Glyph gl; @@ -1882,20 +1922,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.end = i + 1; gl.count = 1; gl.index = p_sd->text[i]; - gl.font_size = p_sd->spans[p_span].font_size; + gl.font_size = fs; gl.font_rid = RID(); - gl.flags = 0; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { gl.flags |= TextServer::GRAPHEME_IS_RTL; } if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x; - p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + gl.advance = get_hex_code_box_size(fs, gl.index).x; + p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f)); + p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f)); } else { - gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + gl.advance = get_hex_code_box_size(fs, gl.index).y; + p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); + p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); } p_sd->width += gl.advance; @@ -1905,7 +1944,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star return; } - hb_font_t *hb_font = fd->get_hb_handle(p_sd->spans[p_span].font_size); + hb_font_t *hb_font = fd->get_hb_handle(fs); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -1981,17 +2020,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.count = 0; gl.font_rid = p_fonts[p_fb_index]; - gl.font_size = p_sd->spans[p_span].font_size; + gl.font_size = fs; gl.index = glyph_info[i].codepoint; if (gl.index != 0) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - gl.advance = glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(gl.font_size)); + gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs))); } else { - gl.advance = -glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(gl.font_size)); + gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs))); } - gl.x_off = glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(gl.font_size)); - gl.y_off = -glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(gl.font_size)); + gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs))); + gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs))); } if (p_sd->preserve_control) { @@ -2026,14 +2065,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } for (int j = 0; j < w[i].count; j++) { if (p_sd->orientation == ORIENTATION_HORIZONTAL) { - p_sd->ascent = MAX(p_sd->ascent, MAX(fd->get_ascent(w[i + j].font_size), w[i + j].y_off)); - p_sd->descent = MAX(p_sd->descent, MAX(fd->get_descent(w[i + j].font_size), w[i + j].y_off)); + p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); + p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - p_sd->ascent = MAX(p_sd->ascent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5); - p_sd->descent = MAX(p_sd->descent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5); + p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5)); + p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5)); } - p_sd->upos = MAX(p_sd->upos, font_get_underline_position(w[i + j].font_rid, w[i + j].font_size)); - p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(w[i + j].font_rid, w[i + j].font_size)); p_sd->width += w[i + j].advance; p_sd->glyphs.push_back(w[i + j]); } @@ -2051,6 +2088,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star if (failed_subrun_start != p_end + 1) { _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); } + p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs)); + p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs)); + p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs)); + p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs)); } } @@ -2180,8 +2221,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); @@ -2195,8 +2236,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); @@ -2207,7 +2248,6 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { gl.start = span.start; gl.end = span.end; gl.count = 1; - gl.index = 0; gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL; if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = sd->objects[span.embedded_key].rect.size.x; @@ -2507,9 +2547,11 @@ void TextServerAdvanced::register_server() { } TextServerAdvanced::TextServerAdvanced() { + hb_bmp_create_font_funcs(); } TextServerAdvanced::~TextServerAdvanced() { + hb_bmp_free_font_funcs(); u_cleanup(); #ifndef ICU_STATIC_DATA if (icu_data != nullptr) { diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index f26b87f67e..8c26554158 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -138,6 +138,10 @@ public: virtual bool font_get_antialiased(RID p_font) const override; virtual Dictionary font_get_feature_list(RID p_font) const override; + virtual Dictionary font_get_variation_list(RID p_font) const override; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override; + virtual double font_get_variation(RID p_font, const String &p_name) const override; virtual void font_set_hinting(RID p_font, Hinting p_hinting) override; virtual Hinting font_get_hinting(RID p_font) const override; diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp index 5ab8edbd71..99cbccb69a 100644 --- a/modules/text_server_fb/bitmap_font_fb.cpp +++ b/modules/text_server_fb/bitmap_font_fb.cpp @@ -198,7 +198,6 @@ Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_s chr.rect.position.y = c[2]; chr.rect.size.x = c[3]; chr.rect.size.y = c[4]; - chr.texture_idx = 0; if (c[7] < 0) { chr.advance.x = c[3]; } else { diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 6feeaec102..6731870e8f 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -33,8 +33,6 @@ #include FT_STROKER_H #include FT_ADVANCES_H -HashMap<String, Vector<uint8_t>> DynamicFontDataFallback::font_mem_cache; - DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(int p_size, int p_outline_size) { ERR_FAIL_COND_V(!valid, nullptr); ERR_FAIL_COND_V(p_size < 0 || p_size > UINT16_MAX, nullptr); @@ -55,11 +53,10 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( if (E != nullptr) { fds = E->get(); } else { - // FT_OPEN_STREAM is extremely slow only on Android. - if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) { - if (font_mem_cache.has(font_path)) { - font_mem = font_mem_cache[font_path].ptr(); - font_mem_size = font_mem_cache[font_path].size(); + if (font_mem == nullptr && font_path != String()) { + if (!font_mem_cache.empty()) { + font_mem = font_mem_cache.ptr(); + font_mem_size = font_mem_cache.size(); } else { FileAccess *f = FileAccess::open(font_path, FileAccess::READ); if (!f) { @@ -67,11 +64,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( } size_t len = f->get_len(); - font_mem_cache[font_path] = Vector<uint8_t>(); - Vector<uint8_t> &fontdata = font_mem_cache[font_path]; - fontdata.resize(len); - f->get_buffer(fontdata.ptrw(), len); - font_mem = fontdata.ptr(); + font_mem_cache.resize(len); + f->get_buffer(font_mem_cache.ptrw(), len); + font_mem = font_mem_cache.ptr(); font_mem_size = len; f->close(); } @@ -79,27 +74,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( int error = 0; fds = memnew(DataAtSize); - if (font_mem == nullptr && font_path != String()) { - FileAccess *f = FileAccess::open(font_path, FileAccess::READ); - if (!f) { - memdelete(fds); - ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'."); - } - - memset(&fds->stream, 0, sizeof(FT_StreamRec)); - fds->stream.base = nullptr; - fds->stream.size = f->get_len(); - fds->stream.pos = 0; - fds->stream.descriptor.pointer = f; - fds->stream.read = _ft_stream_io; - fds->stream.close = _ft_stream_close; - - FT_Open_Args fargs; - memset(&fargs, 0, sizeof(FT_Open_Args)); - fargs.flags = FT_OPEN_STREAM; - fargs.stream = &fds->stream; - error = FT_Open_Face(library, &fargs, 0, &fds->face); - } else if (font_mem) { + if (font_mem) { memset(&fds->stream, 0, sizeof(FT_StreamRec)); fds->stream.base = (unsigned char *)font_mem; fds->stream.size = font_mem_size; @@ -161,30 +136,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size( return fds; } -unsigned long DynamicFontDataFallback::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - - if (f->get_position() != offset) { - f->seek(offset); - } - if (count == 0) { - return 0; - } - - return f->get_buffer(buffer, count); -} - -void DynamicFontDataFallback::_ft_stream_close(FT_Stream stream) { - FileAccess *f = (FileAccess *)stream->descriptor.pointer; - f->close(); - memdelete(f); -} - DynamicFontDataFallback::TexturePosition DynamicFontDataFallback::find_texture_pos_for_glyph(DynamicFontDataFallback::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) { TexturePosition ret; ret.index = -1; - ret.x = 0; - ret.y = 0; int mw = p_width; int mh = p_height; diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h index 060b8cfbf9..6ac8cb52a8 100644 --- a/modules/text_server_fb/dynamic_font_fb.h +++ b/modules/text_server_fb/dynamic_font_fb.h @@ -107,7 +107,7 @@ private: const uint8_t *font_mem = nullptr; int font_mem_size = 0; String font_path; - static HashMap<String, Vector<uint8_t>> font_mem_cache; + Vector<uint8_t> font_mem_cache; float rect_margin = 1.f; int base_size = 16; @@ -119,9 +119,6 @@ private: Map<CacheID, DataAtSize *> size_cache; Map<CacheID, DataAtSize *> size_cache_outline; - static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void _ft_stream_close(FT_Stream stream); - DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0); TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index e74a1d9ef9..383250996d 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -625,7 +625,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->width = 0; sd->upos = 0; sd->uthk = 0; - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + const FontDataFallback *fd = nullptr; + RID prev_rid = RID(); + + for (int i = 0; i < sd_size; i++) { Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { @@ -645,8 +649,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); @@ -661,8 +665,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); @@ -671,25 +675,28 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, sd->glyphs.write[i].advance = sd->objects[key].rect.size.y; } } else { - const FontDataFallback *fd = font_owner.getornull(gl.font_rid); + if (prev_rid != gl.font_rid) { + fd = font_owner.getornull(gl.font_rid); + prev_rid = gl.font_rid; + } if (fd != nullptr) { if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size)); sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance * gl.repeat; @@ -760,21 +767,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (p_length > 0) { new_sd->text = sd->text.substr(p_start, p_length); + int sd_size = sd->glyphs.size(); + const Glyph *sd_glyphs = sd->glyphs.ptr(); - for (int i = 0; i < sd->glyphs.size(); i++) { - if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) { - Glyph gl = sd->glyphs[i]; + for (int i = 0; i < sd_size; i++) { + if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) { + Glyph gl = sd_glyphs[i]; Variant key; + bool find_embedded = false; if (gl.count == 1) { for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (E->get().pos == gl.start) { + find_embedded = true; key = E->key(); new_sd->objects[key] = E->get(); break; } } } - if (key != Variant()) { + if (find_embedded) { if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; @@ -783,8 +794,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); @@ -798,8 +809,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); } break; case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2); - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2); + new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); + new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); @@ -813,17 +824,17 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->ascent = MAX(new_sd->ascent, fd->get_ascent(gl.font_size)); new_sd->descent = MAX(new_sd->descent, fd->get_descent(gl.font_size)); } else { - new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { - new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } new_sd->width += gl.advance * gl.repeat; @@ -943,7 +954,7 @@ float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { float old_adv = gl.advance; - gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size); + gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size)); sd->width += (gl.advance - old_adv); } } @@ -978,8 +989,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float delta = -1; } + Glyph *gl = sd->glyphs.ptrw(); + for (int i = start; i != end; i += delta) { - if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { + if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; @@ -988,13 +1001,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float tab_index = 0; } } - float old_adv = sd->glyphs.write[i].advance; - sd->glyphs.write[i].advance = (tab_off - off); - sd->width += sd->glyphs.write[i].advance - old_adv; + float old_adv = gl[i].advance; + gl[i].advance = tab_off - off; + sd->width += gl[i].advance - old_adv; off = 0; continue; } - off += sd->glyphs[i].advance * sd->glyphs[i].repeat; + off += gl[i].advance * gl[i].repeat; } return 0.f; @@ -1012,7 +1025,8 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { return true; // Noting to do. } - for (int i = 0; i < sd->glyphs.size(); i++) { + int sd_size = sd->glyphs.size(); + for (int i = 0; i < sd_size; i++) { if (sd->glyphs[i].count > 0) { char32_t c = sd->text[sd->glyphs[i].start]; if (is_whitespace(c) && !is_linebreak(c)) { @@ -1086,8 +1100,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); @@ -1101,8 +1115,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); } break; case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2); - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2); + sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); + sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); } break; case VALIGN_BOTTOM: { sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); @@ -1157,14 +1171,14 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { sd->descent = MAX(sd->descent, fd->get_descent(gl.font_size)); } else { gl.advance = fd->get_advance(gl.index, gl.font_size).y; - gl.x_off = -fd->get_advance(gl.index, gl.font_size).x * 0.5; + gl.x_off = -Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5); gl.y_off = fd->get_ascent(gl.font_size); - sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5); - sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5); + sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5)); } } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size)); + sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size)); // Add kerning to previous glyph. if (sd->glyphs.size() > 0) { @@ -1181,12 +1195,12 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f)); } else { gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y; - sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); - sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f); + sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); } } sd->width += gl.advance; diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index b10d4523f2..f9ef184579 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2367,7 +2367,7 @@ void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p binds.push_back(p_binds[i]); } binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing - p_obj->connect_compat(p_signal, this, "_signal_callback", binds, CONNECT_ONESHOT); + p_obj->connect(p_signal, Callable(this, "_signal_callback"), binds, CONNECT_ONESHOT); } bool VisualScriptFunctionState::is_valid() const { diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index d0744fa313..67d3f1bebd 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -278,7 +278,7 @@ if webm_cpu_x86: try: yasm_found = True subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate() - except: + except Exception: yasm_found = False if yasm_found: break diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js index f725a10a6f..9f029407d2 100644 --- a/modules/webrtc/library_godot_webrtc.js +++ b/modules/webrtc/library_godot_webrtc.js @@ -90,6 +90,7 @@ const GodotRTCDataChannel = { }, }, + godot_js_rtc_datachannel_ready_state_get__sig: 'ii', godot_js_rtc_datachannel_ready_state_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -109,6 +110,7 @@ const GodotRTCDataChannel = { } }, + godot_js_rtc_datachannel_send__sig: 'iiiii', godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) { const ref = IDHandler.get(p_id); if (!ref) { @@ -129,14 +131,17 @@ const GodotRTCDataChannel = { return 0; }, + godot_js_rtc_datachannel_is_ordered__sig: 'ii', godot_js_rtc_datachannel_is_ordered: function (p_id) { return IDHandler.get_prop(p_id, 'ordered', true); }, + godot_js_rtc_datachannel_id_get__sig: 'ii', godot_js_rtc_datachannel_id_get: function (p_id) { return IDHandler.get_prop(p_id, 'id', 65535); }, + godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii', godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -151,14 +156,17 @@ const GodotRTCDataChannel = { return 65535; }, + godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii', godot_js_rtc_datachannel_max_retransmits_get: function (p_id) { return IDHandler.get_prop(p_id, 'maxRetransmits', 65535); }, - godot_js_rtc_datachannel_is_negotiated: function (p_id, p_def) { + godot_js_rtc_datachannel_is_negotiated__sig: 'ii', + godot_js_rtc_datachannel_is_negotiated: function (p_id) { return IDHandler.get_prop(p_id, 'negotiated', 65535); }, + godot_js_rtc_datachannel_label_get__sig: 'ii', godot_js_rtc_datachannel_label_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref || !ref.label) { @@ -167,6 +175,7 @@ const GodotRTCDataChannel = { return GodotRuntime.allocString(ref.label); }, + godot_js_rtc_datachannel_protocol_get__sig: 'ii', godot_js_rtc_datachannel_protocol_get: function (p_id) { const ref = IDHandler.get(p_id); if (!ref || !ref.protocol) { @@ -175,11 +184,13 @@ const GodotRTCDataChannel = { return GodotRuntime.allocString(ref.protocol); }, + godot_js_rtc_datachannel_destroy__sig: 'vi', godot_js_rtc_datachannel_destroy: function (p_id) { GodotRTCDataChannel.close(p_id); IDHandler.remove(p_id); }, + godot_js_rtc_datachannel_connect__sig: 'viiiiii', godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) { const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref); const onmessage = GodotRuntime.get_func(p_on_message).bind(null, p_ref); @@ -188,6 +199,7 @@ const GodotRTCDataChannel = { GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose); }, + godot_js_rtc_datachannel_close__sig: 'vi', godot_js_rtc_datachannel_close: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -280,6 +292,7 @@ const GodotRTCPeerConnection = { }, }, + godot_js_rtc_pc_create__sig: 'iiiiii', godot_js_rtc_pc_create: function (p_config, p_ref, p_on_state_change, p_on_candidate, p_on_datachannel) { const onstatechange = GodotRuntime.get_func(p_on_state_change).bind(null, p_ref); const oncandidate = GodotRuntime.get_func(p_on_candidate).bind(null, p_ref); @@ -302,6 +315,7 @@ const GodotRTCPeerConnection = { return id; }, + godot_js_rtc_pc_close__sig: 'vi', godot_js_rtc_pc_close: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -310,6 +324,7 @@ const GodotRTCPeerConnection = { ref.close(); }, + godot_js_rtc_pc_destroy__sig: 'vi', godot_js_rtc_pc_destroy: function (p_id) { const ref = IDHandler.get(p_id); if (!ref) { @@ -321,6 +336,7 @@ const GodotRTCPeerConnection = { IDHandler.remove(p_id); }, + godot_js_rtc_pc_offer_create__sig: 'viiii', godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -335,6 +351,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_local_description_set__sig: 'viiiii', godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -351,6 +368,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_remote_description_set__sig: 'viiiiii', godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) { const ref = IDHandler.get(p_id); if (!ref) { @@ -375,6 +393,7 @@ const GodotRTCPeerConnection = { }); }, + godot_js_rtc_pc_ice_candidate_add__sig: 'viiii', godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) { const ref = IDHandler.get(p_id); if (!ref) { @@ -390,6 +409,7 @@ const GodotRTCPeerConnection = { }, godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'], + godot_js_rtc_pc_datachannel_create__sig: 'iiii', godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) { try { const ref = IDHandler.get(p_id); diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js index 6ada4e7335..cf2c00a6a6 100644 --- a/modules/websocket/library_godot_websocket.js +++ b/modules/websocket/library_godot_websocket.js @@ -135,6 +135,7 @@ const GodotWebSocket = { }, }, + godot_js_websocket_create__sig: 'iiiiiiii', godot_js_websocket_create: function (p_ref, p_url, p_proto, p_on_open, p_on_message, p_on_error, p_on_close) { const on_open = GodotRuntime.get_func(p_on_open).bind(null, p_ref); const on_message = GodotRuntime.get_func(p_on_message).bind(null, p_ref); @@ -156,6 +157,7 @@ const GodotWebSocket = { return GodotWebSocket.create(socket, on_open, on_message, on_error, on_close); }, + godot_js_websocket_send__sig: 'iiiii', godot_js_websocket_send: function (p_id, p_buf, p_buf_len, p_raw) { const bytes_array = new Uint8Array(p_buf_len); let i = 0; @@ -169,12 +171,14 @@ const GodotWebSocket = { return GodotWebSocket.send(p_id, out); }, + godot_js_websocket_close__sig: 'viii', godot_js_websocket_close: function (p_id, p_code, p_reason) { const code = p_code; const reason = GodotRuntime.parseString(p_reason); GodotWebSocket.close(p_id, code, reason); }, + godot_js_websocket_destroy__sig: 'vi', godot_js_websocket_destroy: function (p_id) { GodotWebSocket.destroy(p_id); }, |