summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rw-r--r--COPYRIGHT.txt4
-rw-r--r--SConstruct15
-rw-r--r--core/config/project_settings.cpp4
-rw-r--r--core/core_bind.cpp4
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/crypto/crypto.cpp4
-rw-r--r--core/debugger/engine_debugger.cpp2
-rw-r--r--core/debugger/remote_debugger_peer.cpp7
-rw-r--r--core/input/input.cpp4
-rw-r--r--core/input/input_map.cpp1
-rw-r--r--core/io/compression.cpp6
-rw-r--r--core/io/config_file.cpp5
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/file_access_compressed.cpp6
-rw-r--r--core/io/file_access_encrypted.cpp4
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_network.cpp3
-rw-r--r--core/io/file_access_pack.cpp3
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/multiplayer_api.cpp8
-rw-r--r--core/io/packet_peer_udp.cpp2
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--core/io/resource_importer.h3
-rw-r--r--core/io/resource_loader.cpp6
-rw-r--r--core/io/translation_loader_po.cpp2
-rw-r--r--core/io/xml_parser.cpp2
-rw-r--r--core/math/basis.cpp6
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/geometry_2d.cpp6
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/triangulate.cpp2
-rw-r--r--core/object/method_bind.h1
-rw-r--r--core/object/object.cpp8
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/os/pool_allocator.cpp2
-rw-r--r--core/string/compressed_translation.cpp2
-rw-r--r--core/string/translation.cpp2
-rw-r--r--core/string/translation_po.cpp2
-rw-r--r--core/string/ustring.cpp4
-rw-r--r--core/variant/array.cpp2
-rw-r--r--core/variant/binder_common.h164
-rw-r--r--core/variant/callable.cpp4
-rw-r--r--core/variant/variant.h3
-rw-r--r--core/variant/variant_call.cpp157
-rw-r--r--core/variant/variant_setget.cpp2
-rw-r--r--doc/classes/@GlobalScope.xml8
-rw-r--r--doc/classes/AABB.xml48
-rw-r--r--doc/classes/AStar.xml2
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/Array.xml28
-rw-r--r--doc/classes/AtlasTexture.xml5
-rw-r--r--doc/classes/AudioEffectCapture.xml2
-rw-r--r--doc/classes/BackBufferCopy.xml2
-rw-r--r--doc/classes/BaseMaterial3D.xml4
-rw-r--r--doc/classes/Basis.xml30
-rw-r--r--doc/classes/Callable.xml22
-rw-r--r--doc/classes/Camera3D.xml2
-rw-r--r--doc/classes/CanvasItem.xml2
-rw-r--r--doc/classes/CodeEdit.xml2
-rw-r--r--doc/classes/Color.xml130
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml5
-rw-r--r--doc/classes/ConfigFile.xml2
-rw-r--r--doc/classes/CryptoKey.xml4
-rw-r--r--doc/classes/Decal.xml4
-rw-r--r--doc/classes/Dictionary.xml22
-rw-r--r--doc/classes/Directory.xml4
-rw-r--r--doc/classes/EditorFileSystem.xml2
-rw-r--r--doc/classes/EditorInspectorPlugin.xml4
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml2
-rw-r--r--doc/classes/EditorPlugin.xml2
-rw-r--r--doc/classes/EditorVCSInterface.xml2
-rw-r--r--doc/classes/Engine.xml2
-rw-r--r--doc/classes/Font.xml5
-rw-r--r--doc/classes/FontData.xml2
-rw-r--r--doc/classes/Geometry3D.xml2
-rw-r--r--doc/classes/GraphEdit.xml2
-rw-r--r--doc/classes/GraphNode.xml2
-rw-r--r--doc/classes/HTTPClient.xml2
-rw-r--r--doc/classes/HTTPRequest.xml2
-rw-r--r--doc/classes/IP.xml2
-rw-r--r--doc/classes/Image.xml4
-rw-r--r--doc/classes/Input.xml8
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/Label.xml2
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/MenuButton.xml2
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/NavigationAgent2D.xml2
-rw-r--r--doc/classes/NavigationAgent3D.xml2
-rw-r--r--doc/classes/NavigationMesh.xml2
-rw-r--r--doc/classes/NavigationServer2D.xml42
-rw-r--r--doc/classes/NavigationServer3D.xml42
-rw-r--r--doc/classes/Node.xml6
-rw-r--r--doc/classes/NodePath.xml18
-rw-r--r--doc/classes/OS.xml6
-rw-r--r--doc/classes/Object.xml4
-rw-r--r--doc/classes/PackedByteArray.xml24
-rw-r--r--doc/classes/PackedColorArray.xml8
-rw-r--r--doc/classes/PackedFloat32Array.xml8
-rw-r--r--doc/classes/PackedFloat64Array.xml8
-rw-r--r--doc/classes/PackedInt32Array.xml8
-rw-r--r--doc/classes/PackedInt64Array.xml8
-rw-r--r--doc/classes/PackedStringArray.xml8
-rw-r--r--doc/classes/PackedVector2Array.xml8
-rw-r--r--doc/classes/PackedVector3Array.xml8
-rw-r--r--doc/classes/PhysicalBone3D.xml2
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml8
-rw-r--r--doc/classes/Plane.xml20
-rw-r--r--doc/classes/PopupMenu.xml6
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--doc/classes/Quat.xml24
-rw-r--r--doc/classes/RID.xml2
-rw-r--r--doc/classes/Rect2.xml28
-rw-r--r--doc/classes/Rect2i.xml26
-rw-r--r--doc/classes/RenderingServer.xml8
-rw-r--r--doc/classes/ResourceFormatLoader.xml2
-rw-r--r--doc/classes/RigidBody2D.xml2
-rw-r--r--doc/classes/SceneTree.xml2
-rw-r--r--doc/classes/Shape3D.xml2
-rw-r--r--doc/classes/Signal.xml14
-rw-r--r--doc/classes/Skeleton3D.xml2
-rw-r--r--doc/classes/SoftBody3D.xml6
-rw-r--r--doc/classes/Sprite2D.xml4
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml2
-rw-r--r--doc/classes/String.xml200
-rw-r--r--doc/classes/StringName.xml2
-rw-r--r--doc/classes/Tabs.xml2
-rw-r--r--doc/classes/TextParagraph.xml2
-rw-r--r--doc/classes/TextServer.xml4
-rw-r--r--doc/classes/Timer.xml2
-rw-r--r--doc/classes/Transform.xml18
-rw-r--r--doc/classes/Transform2D.xml26
-rw-r--r--doc/classes/Tween.xml2
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/Vector2.xml66
-rw-r--r--doc/classes/Vector2i.xml6
-rw-r--r--doc/classes/Vector3.xml68
-rw-r--r--doc/classes/Vector3i.xml8
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml2
-rw-r--r--doc/classes/VisualShaderNodeDeterminant.xml2
-rw-r--r--doc/classes/VisualShaderNodeExpression.xml2
-rw-r--r--doc/classes/VisualShaderNodeFaceForward.xml2
-rw-r--r--doc/classes/VisualShaderNodeGroupBase.xml4
-rw-r--r--doc/classes/VisualShaderNodeIf.xml2
-rw-r--r--doc/classes/VisualShaderNodeInput.xml2
-rw-r--r--doc/classes/VisualShaderNodeSDFToScreenUV.xml2
-rw-r--r--doc/classes/VisualShaderNodeScreenUVToSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeSmoothStep.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDFNormal.xml2
-rw-r--r--doc/classes/bool.xml3
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp30
-rw-r--r--drivers/unix/file_access_unix.cpp2
-rw-r--r--drivers/unix/thread_posix.cpp4
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp24
-rw-r--r--drivers/vulkan/vulkan_context.cpp6
-rw-r--r--drivers/windows/file_access_windows.cpp2
-rw-r--r--editor/animation_track_editor.cpp70
-rw-r--r--editor/animation_track_editor.h4
-rw-r--r--editor/doc_tools.cpp25
-rw-r--r--editor/editor_export.cpp14
-rw-r--r--editor/editor_file_dialog.cpp4
-rw-r--r--editor/editor_file_system.cpp63
-rw-r--r--editor/editor_file_system.h4
-rw-r--r--editor/editor_inspector.cpp2
-rw-r--r--editor/editor_node.cpp35
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_properties.cpp2
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/editor_spin_slider.cpp8
-rw-r--r--editor/editor_themes.cpp20
-rw-r--r--editor/editor_themes.h3
-rw-r--r--editor/filesystem_dock.cpp35
-rw-r--r--editor/import/editor_import_collada.cpp85
-rw-r--r--editor/import/resource_importer_obj.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp1247
-rw-r--r--editor/import/resource_importer_scene.h89
-rw-r--r--editor/import/scene_import_settings.cpp1199
-rw-r--r--editor/import/scene_import_settings.h199
-rw-r--r--editor/import/scene_importer_mesh.cpp355
-rw-r--r--editor/import/scene_importer_mesh.h18
-rw-r--r--editor/import_dock.cpp156
-rw-r--r--editor/import_dock.h4
-rw-r--r--editor/node_3d_editor_gizmos.cpp8
-rw-r--r--editor/plugin_config_dialog.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp31
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp9
-rw-r--r--editor/plugins/audio_stream_editor_plugin.h19
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp1
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp20
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp2
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/scene_tree_editor.cpp3
-rw-r--r--editor/scene_tree_editor.h1
-rw-r--r--editor/translations/bg.po44
-rw-r--r--editor/translations/da.po22
-rw-r--r--editor/translations/de.po20
-rw-r--r--editor/translations/es.po20
-rw-r--r--editor/translations/es_AR.po20
-rw-r--r--editor/translations/fa.po14
-rw-r--r--editor/translations/fi.po20
-rw-r--r--editor/translations/it.po50
-rw-r--r--editor/translations/ko.po20
-rw-r--r--editor/translations/pl.po20
-rw-r--r--editor/translations/pt.po46
-rw-r--r--editor/translations/pt_BR.po33
-rw-r--r--editor/translations/ru.po18
-rw-r--r--editor/translations/tr.po27
-rw-r--r--editor/translations/uk.po26
-rw-r--r--editor/translations/zh_CN.po40
-rw-r--r--editor/translations/zh_TW.po20
-rw-r--r--main/main.cpp24
-rw-r--r--main/main_builders.py5
-rw-r--r--methods.py6
-rw-r--r--misc/dist/html/manifest.json2
-rwxr-xr-xmisc/hooks/pre-commit-clang-format2
-rw-r--r--modules/bullet/bullet_physics_server.cpp104
-rw-r--r--modules/bullet/bullet_physics_server.h35
-rw-r--r--modules/bullet/bullet_types_converter.cpp2
-rw-r--r--modules/bullet/godot_collision_dispatcher.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp4
-rw-r--r--modules/bullet/shape_bullet.cpp10
-rw-r--r--modules/bullet/soft_body_bullet.cpp65
-rw-r--r--modules/bullet/soft_body_bullet.h22
-rw-r--r--modules/bullet/space_bullet.cpp2
-rw-r--r--modules/csg/csg.cpp10
-rw-r--r--modules/csg/csg_shape.cpp2
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp2
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp1
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp4
-rw-r--r--modules/gdnative/gdnative/aabb.cpp4
-rw-r--r--modules/gdnative/gdnative/array.cpp4
-rw-r--r--modules/gdnative/gdnative/basis.cpp4
-rw-r--r--modules/gdnative/gdnative/callable.cpp4
-rw-r--r--modules/gdnative/gdnative/color.cpp4
-rw-r--r--modules/gdnative/gdnative/dictionary.cpp4
-rw-r--r--modules/gdnative/gdnative/node_path.cpp4
-rw-r--r--modules/gdnative/gdnative/packed_arrays.cpp44
-rw-r--r--modules/gdnative/gdnative/plane.cpp4
-rw-r--r--modules/gdnative/gdnative/quat.cpp4
-rw-r--r--modules/gdnative/gdnative/rect2.cpp8
-rw-r--r--modules/gdnative/gdnative/rid.cpp4
-rw-r--r--modules/gdnative/gdnative/signal.cpp4
-rw-r--r--modules/gdnative/gdnative/string.cpp44
-rw-r--r--modules/gdnative/gdnative/string_name.cpp4
-rw-r--r--modules/gdnative/gdnative/transform.cpp4
-rw-r--r--modules/gdnative/gdnative/transform2d.cpp4
-rw-r--r--modules/gdnative/gdnative/variant.cpp81
-rw-r--r--modules/gdnative/gdnative/vector2.cpp8
-rw-r--r--modules/gdnative/gdnative/vector3.cpp8
-rw-r--r--modules/gdnative/gdnative_api.json598
-rw-r--r--modules/gdnative/include/gdnative/aabb.h1
-rw-r--r--modules/gdnative/include/gdnative/array.h1
-rw-r--r--modules/gdnative/include/gdnative/basis.h1
-rw-r--r--modules/gdnative/include/gdnative/callable.h1
-rw-r--r--modules/gdnative/include/gdnative/color.h1
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h1
-rw-r--r--modules/gdnative/include/gdnative/node_path.h1
-rw-r--r--modules/gdnative/include/gdnative/packed_arrays.h11
-rw-r--r--modules/gdnative/include/gdnative/plane.h1
-rw-r--r--modules/gdnative/include/gdnative/quat.h1
-rw-r--r--modules/gdnative/include/gdnative/rect2.h2
-rw-r--r--modules/gdnative/include/gdnative/rid.h1
-rw-r--r--modules/gdnative/include/gdnative/signal.h1
-rw-r--r--modules/gdnative/include/gdnative/string.h10
-rw-r--r--modules/gdnative/include/gdnative/transform.h1
-rw-r--r--modules/gdnative/include/gdnative/transform2d.h1
-rw-r--r--modules/gdnative/include/gdnative/variant.h4
-rw-r--r--modules/gdnative/include/gdnative/vector2.h2
-rw-r--r--modules/gdnative/include/gdnative/vector3.h2
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp3
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp2
-rw-r--r--modules/gdnative/register_types.cpp2
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp40
-rw-r--r--modules/gdnavigation/gd_navigation_server.h7
-rw-r--r--modules/gdnavigation/nav_map.cpp512
-rw-r--r--modules/gdnavigation/nav_map.h1
-rw-r--r--modules/gdnavigation/nav_region.cpp22
-rw-r--r--modules/gdnavigation/nav_region.h8
-rw-r--r--modules/gdnavigation/nav_utils.h39
-rw-r--r--modules/gdscript/gdscript_compiler.cpp10
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp5
-rw-r--r--modules/gdscript/gdscript_vm.cpp2
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gltf/config.py24
-rw-r--r--modules/gltf/doc_classes/EditorSceneImporterGLTF.xml (renamed from doc/classes/EditorSceneImporterGLTF.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFAccessor.xml (renamed from doc/classes/GLTFAccessor.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFAnimation.xml (renamed from doc/classes/GLTFAnimation.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFBufferView.xml (renamed from doc/classes/GLTFBufferView.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml (renamed from doc/classes/GLTFCamera.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml (renamed from doc/classes/GLTFDocument.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml (renamed from doc/classes/GLTFLight.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml (renamed from doc/classes/GLTFMesh.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml (renamed from doc/classes/GLTFNode.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml (renamed from doc/classes/GLTFSkeleton.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml (renamed from doc/classes/GLTFSkin.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFSpecGloss.xml (renamed from doc/classes/GLTFSpecGloss.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml (renamed from doc/classes/GLTFState.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml (renamed from doc/classes/GLTFTexture.xml)2
-rw-r--r--modules/gltf/doc_classes/PackedSceneGLTF.xml (renamed from doc/classes/PackedSceneGLTF.xml)0
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp4
-rw-r--r--modules/gltf/gltf_document.cpp33
-rw-r--r--modules/gltf/gltf_texture.h2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml6
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp2
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp12
-rw-r--r--modules/mono/SdkPackageVersions.props4
-rw-r--r--modules/mono/csharp_script.cpp22
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs62
-rw-r--r--modules/mono/editor/bindings_generator.cpp78
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp4
-rw-r--r--modules/text_server_adv/SCsub2
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp10
-rw-r--r--modules/text_server_fb/text_server_fb.cpp2
-rw-r--r--modules/upnp/SCsub15
-rw-r--r--modules/upnp/upnp.cpp6
-rw-r--r--modules/visual_script/visual_script.cpp4
-rw-r--r--modules/visual_script/visual_script_editor.cpp2
-rw-r--r--modules/visual_script/visual_script_expression.cpp2
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp6
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp2
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp6
-rw-r--r--modules/xatlas_unwrap/register_types.cpp3
-rw-r--r--platform/android/detect.py5
-rw-r--r--platform/android/file_access_android.cpp3
-rw-r--r--platform/android/java/app/assets/.gitignore2
-rw-r--r--platform/android/java/app/build.gradle8
-rw-r--r--platform/android/java/app/config.gradle21
-rw-r--r--platform/android/java/lib/build.gradle6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java25
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java65
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotHost.java56
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java86
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java23
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java45
-rw-r--r--platform/android/java/nativeSrcsConfigs/README.md2
-rw-r--r--platform/android/java/nativeSrcsConfigs/build.gradle3
-rw-r--r--platform/android/java_class_wrapper.cpp3
-rw-r--r--platform/android/java_godot_io_wrapper.cpp12
-rw-r--r--platform/android/java_godot_lib_jni.cpp15
-rw-r--r--platform/android/java_godot_view_wrapper.cpp7
-rw-r--r--platform/android/java_godot_view_wrapper.h2
-rw-r--r--platform/android/java_godot_wrapper.cpp63
-rw-r--r--platform/android/java_godot_wrapper.h2
-rw-r--r--platform/android/thread_jandroid.cpp27
-rw-r--r--platform/iphone/detect.py2
-rw-r--r--platform/iphone/godot_view.mm12
-rw-r--r--platform/javascript/detect.py18
-rw-r--r--platform/javascript/emscripten_helpers.py6
-rw-r--r--platform/javascript/js/engine/engine.js2
-rw-r--r--platform/linuxbsd/detect.py4
-rw-r--r--platform/osx/detect.py4
-rw-r--r--platform/osx/export/export.cpp5
-rw-r--r--platform/server/detect.py4
-rw-r--r--platform/uwp/detect.py11
-rw-r--r--platform/uwp/os_uwp.cpp8
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/detect.py17
-rw-r--r--platform/windows/display_server_windows.cpp6
-rw-r--r--platform/windows/joypad_windows.cpp11
-rw-r--r--platform/windows/os_windows.cpp2
-rw-r--r--platform/windows/windows_terminal_logger.cpp5
-rw-r--r--scene/2d/animated_sprite_2d.cpp209
-rw-r--r--scene/2d/animated_sprite_2d.h67
-rw-r--r--scene/2d/line_builder.cpp8
-rw-r--r--scene/2d/navigation_region_2d.cpp70
-rw-r--r--scene/2d/navigation_region_2d.h1
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/sprite_2d.cpp50
-rw-r--r--scene/2d/sprite_2d.h12
-rw-r--r--scene/3d/area_3d.cpp4
-rw-r--r--scene/3d/baked_lightmap.cpp10
-rw-r--r--scene/3d/camera_3d.cpp4
-rw-r--r--scene/3d/collision_object_3d.cpp3
-rw-r--r--scene/3d/gpu_particles_3d.cpp2
-rw-r--r--scene/3d/node_3d.cpp2
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/3d/ray_cast_3d.cpp4
-rw-r--r--scene/3d/skeleton_ik_3d.cpp6
-rw-r--r--scene/3d/soft_body_3d.cpp72
-rw-r--r--scene/3d/soft_body_3d.h20
-rw-r--r--scene/3d/sprite_3d.cpp28
-rw-r--r--scene/3d/sprite_3d.h12
-rw-r--r--scene/3d/vehicle_body_3d.cpp2
-rw-r--r--scene/3d/voxelizer.cpp4
-rw-r--r--scene/animation/animation_player.cpp8
-rw-r--r--scene/animation/animation_tree.cpp7
-rw-r--r--scene/animation/tween.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp2
-rw-r--r--scene/debugger/scene_debugger.cpp2
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/box_container.h2
-rw-r--r--scene/gui/control.cpp6
-rw-r--r--scene/gui/file_dialog.cpp4
-rw-r--r--scene/gui/graph_edit.cpp31
-rw-r--r--scene/gui/graph_node.cpp132
-rw-r--r--scene/gui/item_list.cpp2
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/popup_menu.cpp3
-rw-r--r--scene/gui/rich_text_label.cpp23
-rw-r--r--scene/gui/tab_container.cpp3
-rw-r--r--scene/gui/text_edit.cpp14
-rw-r--r--scene/gui/tree.cpp16
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/http_request.cpp2
-rw-r--r--scene/main/node.cpp8
-rw-r--r--scene/main/scene_tree.cpp1
-rw-r--r--scene/main/viewport.cpp10
-rw-r--r--scene/main/window.cpp3
-rw-r--r--scene/resources/animation.cpp4
-rw-r--r--scene/resources/bit_map.cpp2
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp37
-rw-r--r--scene/resources/concave_polygon_shape_3d.h6
-rw-r--r--scene/resources/material.cpp4
-rw-r--r--scene/resources/particles_material.cpp2
-rw-r--r--scene/resources/polygon_path_finder.cpp4
-rw-r--r--scene/resources/ray_shape_2d.cpp28
-rw-r--r--scene/resources/resource_format_text.cpp2
-rw-r--r--scene/resources/sprite_frames.cpp241
-rw-r--r--scene/resources/sprite_frames.h102
-rw-r--r--scene/resources/surface_tool.cpp9
-rw-r--r--scene/resources/surface_tool.h3
-rw-r--r--scene/resources/world_2d.cpp2
-rw-r--r--servers/audio/effects/audio_effect_capture.cpp2
-rw-r--r--servers/camera/camera_feed.cpp10
-rw-r--r--servers/camera/camera_feed.h6
-rw-r--r--servers/navigation_server_2d.cpp18
-rw-r--r--servers/navigation_server_2d.h9
-rw-r--r--servers/navigation_server_3d.cpp7
-rw-r--r--servers/navigation_server_3d.h9
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp43
-rw-r--r--servers/physics_3d/body_3d_sw.cpp12
-rw-r--r--servers/physics_3d/body_3d_sw.h6
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp332
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h85
-rw-r--r--servers/physics_3d/collision_object_3d_sw.h7
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp206
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp158
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h6
-rw-r--r--servers/physics_3d/gjk_epa.cpp99
-rw-r--r--servers/physics_3d/gjk_epa.h2
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp281
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h81
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h15
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp59
-rw-r--r--servers/physics_3d/shape_3d_sw.h28
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp1221
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h247
-rw-r--r--servers/physics_3d/space_3d_sw.cpp52
-rw-r--r--servers/physics_3d/space_3d_sw.h6
-rw-r--r--servers/physics_3d/step_3d_sw.cpp33
-rw-r--r--servers/physics_server_3d.cpp5
-rw-r--r--servers/physics_server_3d.h26
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub55
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--tests/test_physics_3d.cpp6
-rw-r--r--thirdparty/README.md18
-rw-r--r--thirdparty/harfbuzz/NEWS15
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-common.hh115
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh32
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.cc22
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.h90
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh183
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-atomic.hh129
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.cc27
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.h12
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-serialize.cc42
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.cc107
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.h59
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh97
-rw-r--r--thirdparty/harfbuzz/src/hb-common.cc50
-rw-r--r--thirdparty/harfbuzz/src/hb-common.h741
-rw-r--r--thirdparty/harfbuzz/src/hb-coretext.cc18
-rw-r--r--thirdparty/harfbuzz/src/hb-deprecated.h93
-rw-r--r--thirdparty/harfbuzz/src/hb-directwrite.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-dispatch.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc14
-rw-r--r--thirdparty/harfbuzz/src/hb-face.h15
-rw-r--r--thirdparty/harfbuzz/src/hb-face.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-font.h167
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc38
-rw-r--r--thirdparty/harfbuzz/src/hb-gdi.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-gobject-structs.h32
-rw-r--r--thirdparty/harfbuzz/src/hb-graphite2.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-iter.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-map.cc9
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h8
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-mutex.hh18
-rw-r--r--thirdparty/harfbuzz/src/hb-object.hh17
-rw-r--r--thirdparty/harfbuzz/src/hb-open-file.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh46
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color.cc11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-deprecated.h18
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-glyf-table.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-head-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh51
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh124
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh250
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc127
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.h66
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math.h85
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-meta.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-meta.h3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-metrics.cc31
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-metrics.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc47
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh111
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc112
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh22
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh705
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl113
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc104
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh69
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh89
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc100
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh41
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc15
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh1099
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc)95
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc160
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh96
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc61
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex.hh44
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc41
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag-table.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc29
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var.cc10
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var.h29
-rw-r--r--thirdparty/harfbuzz/src/hb-sanitize.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-set.cc33
-rw-r--r--thirdparty/harfbuzz/src/hb-set.h8
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh87
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-style.cc1
-rw-r--r--thirdparty/harfbuzz/src/hb-style.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc27
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.cc10
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.h50
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h37
-rw-r--r--thirdparty/harfbuzz/src/hb.hh196
-rw-r--r--thirdparty/mbedtls/include/mbedtls/config.h17
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ctr_drbg.h45
-rw-r--r--thirdparty/mbedtls/include/mbedtls/entropy.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/hmac_drbg.h58
-rw-r--r--thirdparty/mbedtls/include/mbedtls/net_sockets.h18
-rw-r--r--thirdparty/mbedtls/include/mbedtls/rsa.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/threading.h3
-rw-r--r--thirdparty/mbedtls/include/mbedtls/version.h8
-rw-r--r--thirdparty/mbedtls/library/base64.c131
-rw-r--r--thirdparty/mbedtls/library/bignum.c6
-rw-r--r--thirdparty/mbedtls/library/ctr_drbg.c16
-rw-r--r--thirdparty/mbedtls/library/ecdsa.c8
-rw-r--r--thirdparty/mbedtls/library/ecjpake.c11
-rw-r--r--thirdparty/mbedtls/library/entropy.c7
-rw-r--r--thirdparty/mbedtls/library/hmac_drbg.c20
-rw-r--r--thirdparty/mbedtls/library/net_sockets.c14
-rw-r--r--thirdparty/mbedtls/library/pkwrite.c22
-rw-r--r--thirdparty/mbedtls/library/rsa.c28
-rw-r--r--thirdparty/mbedtls/library/threading.c6
-rw-r--r--thirdparty/mbedtls/library/version_features.c3
-rw-r--r--thirdparty/miniupnpc/LICENSE5
-rw-r--r--thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c79
-rw-r--r--thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h14
-rw-r--r--thirdparty/miniupnpc/miniupnpc/connecthostport.c6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/listdevices.c197
-rw-r--r--thirdparty/miniupnpc/miniupnpc/minisoap.c6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/minissdpc.c234
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc.c35
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc.h6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c721
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniwget.c15
-rw-r--r--thirdparty/miniupnpc/miniupnpc/portlistingparse.c2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/receivedata.c10
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnpc.c864
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnpdev.h16
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnperrors.c112
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnperrors.h26
-rw-r--r--thirdparty/miniupnpc/miniupnpc/win32_snprintf.h71
-rw-r--r--thirdparty/miniupnpc/windows_fix.diff16
638 files changed, 14557 insertions, 8589 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88c9e1a8a0..fe5631cefd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,7 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Ability to convert visual shaders to text-based shaders.
- See the [complete list of new functions](https://github.com/godotengine/godot/pull/26164).
- Improved visual scripting.
- - Visual scripting now uses an unified graph where all functions are represented.
+ - Visual scripting now uses a unified graph where all functions are represented.
- Nodes can now be edited directly in the graph.
- Support for fuzzy searching.
- The `tool` mode can now be enabled in visual scripts.
@@ -900,7 +900,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Removed many debugging prints in the console.
- Export templates now display an error dialog if no project was found when starting.
- DynamicFont oversampling is now enabled by default.
-- Nodes' internal logic now consistently use internal physics processing.
+- Nodes' internal logic now consistently uses internal physics processing.
- Allow attaching and clearing scripts on multiple nodes at once.
- Default values are no longer saved in scene and resource files.
- The selection rectangle of 2D nodes is now hidden when not pertinent (no more rectangle for collision shapes).
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index ff24d18e6f..6684978318 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -87,6 +87,8 @@ Files: ./servers/physics_3d/gjk_epa.cpp
./servers/physics_3d/joints/pin_joint_3d_sw.h
./servers/physics_3d/joints/slider_joint_3d_sw.cpp
./servers/physics_3d/joints/slider_joint_3d_sw.h
+ ./servers/physics_3d/soft_body_3d_sw.cpp
+ ./servers/physics_3d/soft_body_3d_sw.h
Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2003-2008, Erwin Coumans
2007-2021, Juan Linietsky, Ariel Manzur.
@@ -269,7 +271,7 @@ License: CC0-1.0
Files: ./thirdparty/miniupnpc/
Comment: MiniUPnPc
-Copyright: 2005-2019, Thomas Bernard
+Copyright: 2005-2021, Thomas Bernard
License: BSD-3-clause
Files: ./thirdparty/minizip/
diff --git a/SConstruct b/SConstruct
index b006dddbe6..aa38e568b5 100644
--- a/SConstruct
+++ b/SConstruct
@@ -115,7 +115,7 @@ opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True
opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
opts.Add("arch", "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", "")
opts.Add(EnumVariable("bits", "Target platform bits", "default", ("default", "32", "64")))
-opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size")))
+opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
@@ -246,13 +246,16 @@ for path in module_search_paths:
# Built-in modules don't have nested modules,
# so save the time it takes to parse directories.
modules = methods.detect_modules(path, recursive=False)
- else: # External.
+ else: # Custom.
modules = methods.detect_modules(path, env_base["custom_modules_recursive"])
+ # Provide default include path for both the custom module search `path`
+ # and the base directory containing custom modules, as it may be different
+ # from the built-in "modules" name (e.g. "custom_modules/summator/summator.h"),
+ # so it can be referenced simply as `#include "summator/summator.h"`
+ # independently of where a module is located on user's filesystem.
+ env_base.Prepend(CPPPATH=[path, os.path.dirname(path)])
# Note: custom modules can override built-in ones.
modules_detected.update(modules)
- include_path = os.path.dirname(path)
- if include_path:
- env_base.Prepend(CPPPATH=[include_path])
# Add module options.
for name, path in modules_detected.items():
@@ -385,7 +388,7 @@ if selected_platform in platform_list:
if not (f[0] in ARGUMENTS): # allow command line to override platform flags
env[f[0]] = f[1]
- # Must happen after the flags definition, so that they can be used by platform detect
+ # Must happen after the flags' definition, so that they can be used by platform detect
detect.configure(env)
# Set our C and C++ standard requirements.
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 02effc2001..f87dc6704e 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -393,7 +393,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (exec_path != "") {
// We do several tests sequentially until one succeeds to find a PCK,
- // and if so we attempt loading it at the end.
+ // and if so, we attempt loading it at the end.
// Attempt with PCK bundled into executable.
bool found = _load_resource_pack(exec_path);
@@ -643,7 +643,6 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
} else if (err != ERR_FILE_NOT_FOUND) {
// If the file exists but can't be loaded, we want to know it.
ERR_PRINT("Couldn't load file '" + p_bin_path + "', error code " + itos(err) + ".");
- return err;
}
// Fallback to text-based project.godot file if binary was not found.
@@ -652,7 +651,6 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
return OK;
} else if (err != ERR_FILE_NOT_FOUND) {
ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err) + ".");
- return err;
}
return err;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 2d6b8e5666..c3d547c2c7 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1377,9 +1377,9 @@ Vector<String> _File::get_csv_line(const String &p_delim) const {
return f->get_csv_line(p_delim);
}
-/**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
+/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
* It's not about the current CPU type but file formats.
- * this flags get reset to false (little endian) on each open
+ * These flags get reset to false (little endian) on each open
*/
void _File::set_endian_swap(bool p_swap) {
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index a99df93638..5abfee05bf 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -564,6 +564,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_REVERSE);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_VIRTUAL);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_FROM_SCRIPT);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_STATIC);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index f43f3e3290..6b3953f588 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -100,7 +100,7 @@ void Crypto::load_default_certificates(String p_path) {
PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg) {
Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
- ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available witout mbedtls module.");
+ ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available without mbedtls module.");
Error err = ctx->start(p_hash_type, p_key);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
err = ctx->update(p_msg);
@@ -108,7 +108,7 @@ PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, Packed
return ctx->finish();
}
-// Compares two HMACS for equality without leaking timing information in order to prevent timing attakcs.
+// Compares two HMACS for equality without leaking timing information in order to prevent timing attacks.
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
bool Crypto::constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received) {
const uint8_t *t = p_trusted.ptr();
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index 895b8c23a9..e5dba029c9 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -192,7 +192,7 @@ void EngineDebugger::deinitialize() {
singleton = nullptr;
}
- // Clear profilers/captuers/protocol handlers.
+ // Clear profilers/captures/protocol handlers.
profilers.clear();
captures.clear();
protocols.clear();
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 857e3af268..90b0975159 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -190,13 +190,18 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
}
void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
+ const uint64_t min_tick = 100;
RemoteDebuggerPeerTCP *peer = (RemoteDebuggerPeerTCP *)p_ud;
while (peer->running && peer->is_peer_connected()) {
+ uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
peer->_poll();
if (!peer->is_peer_connected()) {
break;
}
- peer->tcp_client->poll(NetSocket::POLL_TYPE_IN_OUT, 1);
+ ticks_usec = OS::get_singleton()->get_ticks_usec() - ticks_usec;
+ if (ticks_usec < min_tick) {
+ OS::get_singleton()->delay_usec(min_tick - ticks_usec);
+ }
}
}
diff --git a/core/input/input.cpp b/core/input/input.cpp
index f928ae7654..3a8c1c1628 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -723,7 +723,7 @@ void Input::warp_mouse_position(const Vector2 &p_to) {
Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
// The relative distance reported for the next event after a warp is in the boundaries of the
- // size of the rect on that axis, but it may be greater, in which case there's not problem as fmod()
+ // size of the rect on that axis, but it may be greater, in which case there's no problem as fmod()
// will warp it, but if the pointer has moved in the opposite direction between the pointer relocation
// and the subsequent event, the reported relative distance will be less than the size of the rect
// and thus fmod() will be disabled for handling the situation.
@@ -779,7 +779,7 @@ bool Input::is_emulating_touch_from_mouse() const {
return emulate_touch_from_mouse;
}
-// Calling this whenever the game window is focused helps unstucking the "touch mouse"
+// Calling this whenever the game window is focused helps unsticking the "touch mouse"
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
void Input::ensure_touch_mouse_raised() {
if (mouse_from_touch_index != -1) {
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index e0b25fa092..7d85fd6492 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -567,6 +567,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(KEY_E | KEY_MASK_CTRL));
inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_CMD));
default_builtin_cache.insert("ui_text_caret_line_end.OSX", inputs);
+
// Text Caret Movement Page Up/Down
inputs = List<Ref<InputEvent>>();
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 456023e2a6..980234cbfc 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -181,8 +181,8 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
}
/**
- This will handle both Gzip and Deflat streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
- This is required for compressed data who's final uncompressed size is unknown, as is the case for HTTP response bodies.
+ This will handle both Gzip and Deflate streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
+ This is required for compressed data whose final uncompressed size is unknown, as is the case for HTTP response bodies.
This is much slower however than using Compression::decompress because it may result in multiple full copies of the output buffer.
*/
int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
@@ -248,7 +248,7 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s
out_mark += gzip_chunk;
- // Encorce max output size
+ // Enforce max output size
if (p_max_dst_size > -1 && strm.total_out > (uint64_t)p_max_dst_size) {
(void)inflateEnd(&strm);
p_dst_vect->resize(0);
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 015c1f0d90..10f68f3cef 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -295,6 +295,9 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
return OK;
}
+void ConfigFile::clear() {
+ values.clear();
+}
void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
@@ -317,4 +320,6 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_encrypted", "path", "key"), &ConfigFile::save_encrypted);
ClassDB::bind_method(D_METHOD("save_encrypted_pass", "path", "password"), &ConfigFile::save_encrypted_pass);
+
+ ClassDB::bind_method(D_METHOD("clear"), &ConfigFile::clear);
}
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 386d304f07..1b28257c60 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -68,6 +68,8 @@ public:
Error load(const String &p_path);
Error parse(const String &p_data);
+ void clear();
+
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
Error load_encrypted_pass(const String &p_path, const String &p_pass);
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 9ec2b27e88..b2440629e3 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -286,8 +286,10 @@ uint8_t FileAccessCompressed::get_8() const {
}
int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
- ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+ ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
if (at_end) {
read_eof = true;
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 8b4c57ce64..8ace897f18 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -237,7 +237,9 @@ uint8_t FileAccessEncrypted::get_8() const {
}
int FileAccessEncrypted::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+ ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
int to_copy = MIN(p_length, data.size() - pos);
for (int i = 0; i < to_copy; i++) {
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 04270de77f..58670d5246 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -138,6 +138,8 @@ uint8_t FileAccessMemory::get_8() const {
}
int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!data, -1);
int left = length - pos;
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 97838fd14c..31b7d658d0 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -366,6 +366,9 @@ void FileAccessNetwork::_queue_page(int p_page) const {
}
int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
//bool eof=false;
if (pos + p_length > total_size) {
eof_flag = true;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index faf4fca14f..e24dc40166 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -299,6 +299,9 @@ uint8_t FileAccessPack::get_8() const {
}
int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
if (eof) {
return 0;
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 01f9337a80..586c988974 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -303,6 +303,8 @@ uint8_t FileAccessZip::get_8() const {
}
int FileAccessZip::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!zfile, -1);
at_eof = unzeof(zfile);
if (at_eof) {
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 6b550e69c8..94060cfe0b 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -50,7 +50,7 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas
// Do nothing.
} break;
case MultiplayerAPI::RPC_MODE_REMOTE: {
- // Do nothing also. Remote cannot produce a local call.
+ // Do nothing. Remote cannot produce a local call.
} break;
case MultiplayerAPI::RPC_MODE_MASTERSYNC: {
if (is_master) {
@@ -675,7 +675,7 @@ Error MultiplayerAPI::_encode_and_compress_variant(const Variant &p_variant, uin
return err;
}
if (r_buffer) {
- // The first byte is not used by the marshaling, so store the type
+ // The first byte is not used by the marshalling, so store the type
// so we know how to decompress and decode this variant.
r_buffer[0] = p_variant.get_type();
}
@@ -791,7 +791,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
packet_cache.resize(m_amount);
// Encode meta.
- // The meta is composed by a single byte that contains (starting from the least segnificant bit):
+ // The meta is composed by a single byte that contains (starting from the least significant bit):
// - `NetworkCommands` in the first three bits.
// - `NetworkNodeIdCompression` in the next 2 bits.
// - `NetworkNameIdCompression` in the next 1 bit.
@@ -830,7 +830,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 4;
}
} else {
- // The targets doesn't know the node yet, so we need to use 32 bits int.
+ // The targets don't know the node yet, so we need to use 32 bits int.
node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
MAKE_ROOM(ofs + 4);
encode_uint32(psc->id, &(packet_cache.write[ofs]));
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index d8d63d976f..3f46f2706e 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -224,7 +224,7 @@ Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
// I see no reason why we should get ERR_BUSY (wouldblock/eagain) here.
// This is UDP, so connect is only used to tell the OS to which socket
- // it shuold deliver packets when multiple are bound on the same address/port.
+ // it should deliver packets when multiple are bound on the same address/port.
if (err != OK) {
close();
ERR_FAIL_V_MSG(FAILED, "Unable to connect");
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index fb6ad7d65e..c4eb2a20bb 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1245,7 +1245,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
- return ""; //could not rwead
+ return ""; //could not read
}
ResourceLoaderBinary loader;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 91efec5534..eeb486073e 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -115,6 +115,9 @@ public:
ImportOption() {}
};
+ virtual bool has_advanced_options() const { return false; }
+ virtual void show_advanced_options(const String &p_path) {}
+
virtual int get_preset_count() const { return 0; }
virtual String get_preset_name(int p_idx) const { return String(); }
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 8275dd0ad4..dcf71bb4a9 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -215,7 +215,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
load_task.loader_id = Thread::get_caller_id();
if (load_task.semaphore) {
- //this is an actual thread, so wait for Ok fom semaphore
+ //this is an actual thread, so wait for Ok from semaphore
thread_load_semaphore->wait(); //wait until its ok to start loading
}
load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
@@ -443,7 +443,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
ThreadLoadTask &load_task = thread_load_tasks[local_path];
- //semaphore still exists, meaning its still loading, request poll
+ //semaphore still exists, meaning it's still loading, request poll
Semaphore *semaphore = load_task.semaphore;
if (semaphore) {
load_task.poll_requests++;
@@ -452,7 +452,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
// As we got a semaphore, this means we are going to have to wait
// until the sub-resource is done loading
//
- // As this thread will become 'blocked' we should "echange" its
+ // As this thread will become 'blocked' we should "exchange" its
// active status with a waiting one, to ensure load continues.
//
// This ensures loading is never blocked and that is also within
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 0e11ff514a..9adf912224 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -194,7 +194,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
l = l.substr(1, l.length());
// Find final quote, ignoring escaped ones (\").
// The escape_next logic is necessary to properly parse things like \\"
- // where the blackslash is the one being escaped, not the quote.
+ // where the backslash is the one being escaped, not the quote.
int end_pos = -1;
bool escape_next = false;
for (int i = 0; i < l.length(); i++) {
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 1574634aad..d5eb32513b 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -344,7 +344,7 @@ void XMLParser::_bind_methods() {
}
Error XMLParser::read() {
- // if not end reached, parse the node
+ // if end not reached, parse the node
if (P && (P - data) < (int64_t)length - 1 && *P != 0) {
_parse_current_node();
return OK;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index cbdd8a8c9f..cc2b7c6611 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -132,7 +132,7 @@ bool Basis::is_symmetric() const {
Basis Basis::diagonalize() {
//NOTE: only implemented for symmetric matrices
-//with the Jacobi iterative method method
+//with the Jacobi iterative method
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_symmetric(), Basis());
#endif
@@ -317,7 +317,7 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const {
// Multiplies the matrix from left by the rotation matrix: M -> R.M
// Note that this does *not* rotate the matrix itself.
//
-// The main use of Basis is as Transform.basis, which is used a the transformation matrix
+// The main use of Basis is as Transform.basis, which is used by the transformation matrix
// of 3D object. Rotate here refers to rotation of the object (which is R * (*this)),
// not the matrix itself (which is R * (*this) * R.transposed()).
Basis Basis::rotated(const Vector3 &p_axis, real_t p_phi) const {
@@ -881,7 +881,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
if ((Math::abs(elements[1][0] - elements[0][1]) < epsilon) && (Math::abs(elements[2][0] - elements[0][2]) < epsilon) && (Math::abs(elements[2][1] - elements[1][2]) < epsilon)) {
// singularity found
// first check for identity matrix which must have +1 for all terms
- // in leading diagonaland zero in other terms
+ // in leading diagonal and zero in other terms
if ((Math::abs(elements[1][0] + elements[0][1]) < epsilon2) && (Math::abs(elements[2][0] + elements[0][2]) < epsilon2) && (Math::abs(elements[2][1] + elements[1][2]) < epsilon2) && (Math::abs(elements[0][0] + elements[1][1] + elements[2][2] - 3) < epsilon2)) {
// this singularity is identity matrix so angle = 0
r_axis = Vector3(0, 1, 0);
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 636ea601c7..f7ac44d321 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -978,7 +978,7 @@ Expression::ENode *Expression::_parse_expression() {
}
}
- /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+ /* Reduce the set of expressions and place them in an operator tree, respecting precedence */
while (expression.size() > 1) {
int next_op = -1;
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index d67be14d33..feb1fb2fb8 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -87,9 +87,9 @@ struct _AtlasWorkRectResult {
void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) {
// Super simple, almost brute force scanline stacking fitter.
// It's pretty basic for now, but it tries to make sure that the aspect ratio of the
- // resulting atlas is somehow square. This is necessary because video cards have limits.
- // On texture size (usually 2048 or 4096), so the more square a texture, the more chances.
- // It will work in every hardware.
+ // resulting atlas is somehow square. This is necessary because video cards have limits
+ // on texture size (usually 2048 or 4096), so the squarer a texture, the more the chances
+ // that it will work in every hardware.
// For example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a
// 256x8192 atlas (won't work anywhere).
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index ad28967d7a..fe18cc3d41 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -268,7 +268,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
for (Map<Edge, FaceConnect>::Element *E = lit_edges.front(); E; E = E->next()) {
FaceConnect &fc = E->get();
if (fc.left && fc.right) {
- continue; //edge is uninteresting, not on horizont
+ continue; //edge is uninteresting, not on horizon
}
//create new face!
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index 0047c0705d..fa1588dbc5 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -97,7 +97,7 @@ bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, in
// It can happen that the triangulation ends up with three aligned vertices to deal with.
// In this scenario, making the check below strict may reject the possibility of
- // forming a last triangle with these aligned vertices, preventing the triangulatiom
+ // forming a last triangle with these aligned vertices, preventing the triangulation
// from completing.
// To avoid that we allow zero-area triangles if all else failed.
float threshold = relaxed ? -CMP_EPSILON : CMP_EPSILON;
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 7cf4f8d4e8..7030ae201b 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -42,6 +42,7 @@ enum MethodFlags {
METHOD_FLAG_VIRTUAL = 32,
METHOD_FLAG_FROM_SCRIPT = 64,
METHOD_FLAG_VARARG = 128,
+ METHOD_FLAG_STATIC = 256,
METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL,
};
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 1a9cce49d8..413f917518 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -596,7 +596,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
- if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
+ if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
if (!metadata.is_empty()) {
@@ -1671,7 +1671,7 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName>
for (int i = 1; i < p_path.size(); i++) {
if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) {
- // We cannot be sure about the type of properties this types can have
+ // We cannot be sure about the type of properties this type can have
if (r_valid) {
*r_valid = false;
}
@@ -1719,10 +1719,10 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr);
#endif
- //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of syncro
+ //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync
//just return the same pointer.
//if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it
- //as it should not really affect performance much (won't be called too often), as in far most caes the condition below will be false afterwards
+ //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards
if (!_script_instance_bindings[p_script_language_index]) {
void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 5a3df88619..ad234c2d49 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -368,6 +368,8 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
}
int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
int i = 0;
for (i = 0; i < p_length && !eof_reached(); i++) {
p_dst[i] = get_8();
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index b538ca0c96..9be3a62e2f 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -136,7 +136,7 @@ void PoolAllocator::compact_up(int p_from) {
for (int i = entry_count - 1; i >= p_from; i--) {
Entry &entry = entry_array[entry_indices[i]];
- /* determine hole size to nextious entry */
+ /* determine hole size for next entry */
int hole_size = next_entry_end_pos - (entry.pos + aligned(entry.len));
diff --git a/core/string/compressed_translation.cpp b/core/string/compressed_translation.cpp
index ad90924293..15abf63f7e 100644
--- a/core/string/compressed_translation.cpp
+++ b/core/string/compressed_translation.cpp
@@ -44,7 +44,7 @@ struct _PHashTranslationCmp {
void PHashTranslation::generate(const Ref<Translation> &p_from) {
// This method compresses a Translation instance.
- // Right now it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
+ // Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
#ifdef TOOLS_ENABLED
List<StringName> keys;
p_from->get_message_list(&keys);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 9cee218735..ade5f7b4d8 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -853,7 +853,7 @@ void Translation::set_locale(const String &p_locale) {
locale = univ_locale;
}
- if (OS::get_singleton()->get_main_loop()) {
+ if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(this)) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
}
}
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 846afe761b..42ba30fbe5 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -158,7 +158,7 @@ int TranslationPO::_get_plural_index(int p_n) const {
void TranslationPO::_cache_plural_tests(const String &p_plural_rule) {
// Some examples of p_plural_rule passed in can have the form:
// "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" (Arabic)
- // "n >= 2" (French) // When evaluating the last, esp careful with this one.
+ // "n >= 2" (French) // When evaluating the last, especially careful with this one.
// "n != 1" (English)
int first_ques_mark = p_plural_rule.find("?");
if (first_ques_mark == -1) {
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 9f931ef30b..28228e4a83 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1764,7 +1764,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
if (skip) {
_UNICERROR("no space left");
- return true; //not enough spac
+ return true; //not enough space
}
}
@@ -4480,7 +4480,7 @@ String String::sprintf(const Array &values, bool *error) const {
for (; *self; self++) {
const char32_t c = *self;
- if (in_format) { // We have % - lets see what else we get.
+ if (in_format) { // We have % - let's see what else we get.
switch (c) {
case '%': { // Replace %% with %
formatted += chr(c);
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 9a2922a777..347c6cd82e 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -141,7 +141,7 @@ uint32_t Array::hash() const {
void Array::_assign(const Array &p_array) {
if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
- //same type or untyped, just reference, shuold be fine
+ //same type or untyped, just reference, should be fine
_ref(p_array);
} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
_p->array = p_array._p->array;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 490bd45b7b..8c0b7907e3 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -238,6 +238,16 @@ void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P..
PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
+template <class R, class... P, size_t... Is>
+void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class... P, size_t... Is>
+void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
+ p_method(PtrToArg<P>::convert(p_args[Is])...);
+}
+
template <class T, class... P, size_t... Is>
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
@@ -263,6 +273,16 @@ void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_me
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
+template <class R, class... P, size_t... Is>
+void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class... P, size_t... Is>
+void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
+ p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
template <class T, class... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -456,6 +476,16 @@ void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), con
call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class R, class... P>
+void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_ptr_args_static_method(void (*p_method)(P...), const void **p_args) {
+ call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class... P>
void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
@@ -476,6 +506,16 @@ void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T
call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class... P>
+void call_with_validated_variant_args_static_method(void (*p_method)(P...), const Variant **p_args) {
+ call_with_validated_variant_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
// GCC raises "parameter 'p_args' set but not used" when P = {},
// it's not clever enough to treat other P values as making this branch valid.
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
@@ -566,6 +606,28 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif
}
+template <class R, class... P, size_t... Is>
+void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
+template <class... P, size_t... Is>
+void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
template <class T, class R, class... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -596,6 +658,42 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args;
}
+template <class R, class... P>
+void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -660,6 +758,72 @@ void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T
call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
+template <class R, class... P>
+void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_static_ret(p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_static(p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index bd51e2dd1e..a1d9c5ed2f 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -126,7 +126,7 @@ bool Callable::operator==(const Callable &p_callable) const {
if (custom_a == custom_b) {
if (custom_a) {
if (custom == p_callable.custom) {
- return true; //same pointer, dont even compare
+ return true; //same pointer, don't even compare
}
CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
@@ -155,7 +155,7 @@ bool Callable::operator<(const Callable &p_callable) const {
if (custom_a == custom_b) {
if (custom_a) {
if (custom == p_callable.custom) {
- return false; //same pointer, dont even compare
+ return false; //same pointer, don't even compare
}
CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 5050aa24ec..0acafc64fa 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -495,6 +495,7 @@ public:
static bool has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method);
static Variant::Type get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method);
static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method);
+ static bool is_builtin_method_static(Variant::Type p_type, const StringName &p_method);
static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
static int get_builtin_method_count(Variant::Type p_type);
@@ -502,6 +503,8 @@ public:
void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
+ static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
+
static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 90272ad5b4..8c1d8066d6 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -42,6 +42,16 @@
typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_static_method_call(R (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_static_ret_dv(method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class... P>
+static _FORCE_INLINE_ void vc_static_method_call(void (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_static_dv(method, p_args, p_argcount, r_error, p_defvals);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
@@ -81,6 +91,16 @@ static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Vari
call_with_validated_variant_argsc(base, method, p_args);
}
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_validated_static_call(R (*method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method_ret(method, p_args, r_ret);
+}
+
+template <class... P>
+static _FORCE_INLINE_ void vc_validated_static_call(void (*method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method(method, p_args);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
@@ -150,6 +170,11 @@ static _FORCE_INLINE_ int vc_get_argument_count(R (*method)(T *, P...)) {
return sizeof...(P);
}
+template <class R, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count_static(R (*method)(P...)) {
+ return sizeof...(P);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
@@ -174,6 +199,11 @@ static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (*method)(T *, P...),
return call_get_argument_type<P...>(p_arg);
}
+template <class R, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type_static(R (*method)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
@@ -218,6 +248,16 @@ static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...) const) {
return false;
}
+template <class... P>
+static _FORCE_INLINE_ bool vc_has_return_type_static(void (*method)(P...)) {
+ return false;
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type_static(R (*method)(P...)) {
+ return true;
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...)) {
return false;
@@ -283,6 +323,9 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
static bool is_const() { \
return vc_is_const(m_method_ptr); \
} \
+ static bool is_static() { \
+ return false; \
+ } \
static bool is_vararg() { \
return false; \
} \
@@ -294,6 +337,57 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
} \
};
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_static_ptrcall(R (*method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method_ret<R, P...>(method, p_args, r_ret);
+}
+
+template <class... P>
+static _FORCE_INLINE_ void vc_static_ptrcall(void (*method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method<P...>(method, p_args);
+}
+
+#define STATIC_METHOD_CLASS(m_class, m_method_name, m_method_ptr) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ vc_static_method_call(m_method_ptr, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_change_return_type(m_method_ptr, r_ret); \
+ vc_validated_static_call(m_method_ptr, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_static_ptrcall(m_method_ptr, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count_static(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type_static(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return vc_has_return_type_static(m_method_ptr); \
+ } \
+ static bool is_const() { \
+ return false; \
+ } \
+ static bool is_static() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
@@ -326,6 +420,9 @@ static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, cons
static bool is_const() { \
return true; \
} \
+ static bool is_static() { \
+ return false; \
+ } \
static bool is_vararg() { \
return false; \
} \
@@ -379,6 +476,9 @@ static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, cons
static bool is_const() { \
return true; \
} \
+ static bool is_static() { \
+ return false; \
+ } \
static bool is_vararg() { \
return true; \
} \
@@ -549,6 +649,7 @@ struct VariantBuiltInMethodInfo {
Vector<String> argument_names;
bool is_const;
+ bool is_static;
bool has_return_type;
bool is_vararg;
Variant::Type return_type;
@@ -580,6 +681,7 @@ static void register_builtin_method(const Vector<String> &p_argnames, const Vect
imi.argument_names = p_argnames;
imi.is_const = T::is_const();
+ imi.is_static = T::is_static();
imi.is_vararg = T::is_vararg();
imi.has_return_type = T::has_return_type();
imi.return_type = T::get_return_type();
@@ -625,6 +727,24 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg
}
}
+void Variant::call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+ const VariantBuiltInMethodInfo *imf = builtin_method_info[p_type].lookup_ptr(p_method);
+
+ if (!imf) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ if (!imf->is_static) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+ imf->call(nullptr, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
+}
+
bool Variant::has_method(const StringName &p_method) const {
if (type == OBJECT) {
Object *obj = get_validated_object();
@@ -724,6 +844,13 @@ bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_
return method->is_const;
}
+bool Variant::is_builtin_method_static(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, false);
+ return method->is_static;
+}
+
bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
@@ -759,7 +886,9 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
if (method->is_vararg) {
mi.flags |= METHOD_FLAG_VARARG;
}
-
+ if (method->is_static) {
+ mi.flags |= METHOD_FLAG_STATIC;
+ }
for (int i = 0; i < method->argument_count; i++) {
PropertyInfo pi;
#ifdef DEBUG_METHODS_ENABLED
@@ -855,6 +984,16 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
#endif
#ifdef DEBUG_METHODS_ENABLED
+#define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \
+ STATIC_METHOD_CLASS(m_type, m_method, m_type::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args);
+#else
+#define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \
+ STATIC_METHOD_CLASS(m_type, m_method, m_type ::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \
METHOD_CLASS(m_type, m_name, m_method); \
register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
@@ -983,6 +1122,11 @@ static void _register_variant_builtin_methods() {
bind_method(String, to_utf16_buffer, sarray(), varray());
bind_method(String, to_utf32_buffer, sarray(), varray());
+ bind_static_method(String, num_scientific, sarray("number"), varray());
+ bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
+ bind_static_method(String, chr, sarray("char"), varray());
+ bind_static_method(String, humanize_size, sarray("size"), varray());
+
/* Vector2 */
bind_method(Vector2, angle, sarray(), varray());
@@ -1147,6 +1291,17 @@ static void _register_variant_builtin_methods() {
//ADDFUNC4R(COLOR, COLOR, Color, from_hsv, FLOAT, "h", FLOAT, "s", FLOAT, "v", FLOAT, "a", varray(1.0));
bind_method(Color, is_equal_approx, sarray("to"), varray());
+ bind_static_method(Color, hex, sarray("hex"), varray());
+ bind_static_method(Color, hex64, sarray("hex"), varray());
+ bind_static_method(Color, html, sarray("rgba"), varray());
+ bind_static_method(Color, html_is_valid, sarray("color"), varray());
+ bind_static_method(Color, find_named_color, sarray("name"), varray());
+ bind_static_method(Color, get_named_color_count, sarray(), varray());
+ bind_static_method(Color, get_named_color_name, sarray("idx"), varray());
+ bind_static_method(Color, get_named_color, sarray("idx"), varray());
+ bind_static_method(Color, from_string, sarray("str", "default"), varray());
+ bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray());
+
/* RID */
bind_method(RID, get_id, sarray(), varray());
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index ea8263402a..f9cc7c4ff4 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -2198,7 +2198,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &
}
return;
case STRING: {
- //this is pretty funny and bizarre, but artists like to use it for typewritter effects
+ //this is pretty funny and bizarre, but artists like to use it for typewriter effects
String sa = *reinterpret_cast<const String *>(a._data._mem);
String sb = *reinterpret_cast<const String *>(b._data._mem);
String dst;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index d57d241b53..7e9da01275 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -50,7 +50,7 @@
<argument index="0" name="x" type="float">
</argument>
<description>
- Returns the arc cosine of [code]x[/code] in radians. Use to get the angle of cosine [code]x[/code].
+ Returns the arc cosine of [code]x[/code] in radians. Use to get the angle of cosine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method acos] will return [constant @GDScript.NAN].
[codeblock]
# c is 0.523599 or 30 degrees if converted with rad2deg(c)
c = acos(0.866025)
@@ -63,7 +63,7 @@
<argument index="0" name="x" type="float">
</argument>
<description>
- Returns the arc sine of [code]x[/code] in radians. Use to get the angle of sine [code]x[/code].
+ Returns the arc sine of [code]x[/code] in radians. Use to get the angle of sine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method asin] will return [constant @GDScript.NAN].
[codeblock]
# s is 0.523599 or 30 degrees if converted with rad2deg(s)
s = asin(0.5)
@@ -777,7 +777,7 @@
<return type="int">
</return>
<description>
- Returns a random unsigned 32 bit integer. Use remainder to obtain a random value in the interval [code][0, N - 1][/code] (where N is smaller than 2^32).
+ Returns a random unsigned 32-bit integer. Use remainder to obtain a random value in the interval [code][0, N - 1][/code] (where N is smaller than 2^32).
[codeblock]
randi() # Returns random integer between 0 and 2^32 - 1
randi() % 20 # Returns random integer between 0 and 19
@@ -2530,6 +2530,8 @@
<constant name="METHOD_FLAG_FROM_SCRIPT" value="64" enum="MethodFlags">
Deprecated method flag, unused.
</constant>
+ <constant name="METHOD_FLAG_STATIC" value="256" enum="MethodFlags">
+ </constant>
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags">
Default method flags.
</constant>
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 8cd7e6f5fa..a28bde9946 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -41,14 +41,14 @@
Constructs an [AABB] from a position and size.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="AABB">
</return>
<description>
Returns an AABB with equivalent position and size, modified so that the most-negative corner is the origin and the size is positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
@@ -57,7 +57,7 @@
Returns [code]true[/code] if this [AABB] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="to_point" type="Vector3">
@@ -66,14 +66,14 @@
Returns this [AABB] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="float">
</return>
<description>
Returns the volume of the [AABB].
</description>
</method>
- <method name="get_endpoint">
+ <method name="get_endpoint" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -82,49 +82,49 @@
Gets the position of the 8 endpoints of the [AABB] in space.
</description>
</method>
- <method name="get_longest_axis">
+ <method name="get_longest_axis" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the normalized longest axis of the [AABB].
</description>
</method>
- <method name="get_longest_axis_index">
+ <method name="get_longest_axis_index" qualifiers="const">
<return type="int">
</return>
<description>
Returns the index of the longest axis of the [AABB] (according to [Vector3]'s [code]AXIS_*[/code] constants).
</description>
</method>
- <method name="get_longest_axis_size">
+ <method name="get_longest_axis_size" qualifiers="const">
<return type="float">
</return>
<description>
Returns the scalar length of the longest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis">
+ <method name="get_shortest_axis" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the normalized shortest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis_index">
+ <method name="get_shortest_axis_index" qualifiers="const">
<return type="int">
</return>
<description>
Returns the index of the shortest axis of the [AABB] (according to [Vector3]::AXIS* enum).
</description>
</method>
- <method name="get_shortest_axis_size">
+ <method name="get_shortest_axis_size" qualifiers="const">
<return type="float">
</return>
<description>
Returns the scalar length of the shortest axis of the [AABB].
</description>
</method>
- <method name="get_support">
+ <method name="get_support" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="dir" type="Vector3">
@@ -133,7 +133,7 @@
Returns the support point in a given direction. This is useful for collision detection algorithms.
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="by" type="float">
@@ -142,21 +142,21 @@
Returns a copy of the [AABB] grown a given amount of units towards all the sides.
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [AABB] is flat or empty.
</description>
</method>
- <method name="has_no_surface">
+ <method name="has_no_surface" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [AABB] is empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -165,7 +165,7 @@
Returns [code]true[/code] if the [AABB] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
@@ -174,7 +174,7 @@
Returns the intersection between two [AABB]. An empty AABB (size 0,0,0) is returned on failure.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
@@ -183,7 +183,7 @@
Returns [code]true[/code] if the [AABB] overlaps with another.
</description>
</method>
- <method name="intersects_plane">
+ <method name="intersects_plane" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="plane" type="Plane">
@@ -192,7 +192,7 @@
Returns [code]true[/code] if the [AABB] is on both sides of a plane.
</description>
</method>
- <method name="intersects_ray">
+ <method name="intersects_ray" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -202,7 +202,7 @@
<description>
</description>
</method>
- <method name="intersects_segment">
+ <method name="intersects_segment" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -213,7 +213,7 @@
Returns [code]true[/code] if the [AABB] intersects the line segment between [code]from[/code] and [code]to[/code].
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="aabb" type="AABB">
@@ -222,7 +222,7 @@
Returns [code]true[/code] if this [AABB] and [code]aabb[/code] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
@@ -264,7 +264,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml
index bfdc66623d..e975b8ed28 100644
--- a/doc/classes/AStar.xml
+++ b/doc/classes/AStar.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AStar" inherits="Reference" version="4.0">
<brief_description>
- An implementation of A* to find shortest paths among connected points in space.
+ An implementation of A* to find the shortest paths among connected points in space.
</brief_description>
<description>
A* (A star) is a computer algorithm that is widely used in pathfinding and graph traversal, the process of plotting short paths among vertices (points), passing through a given set of edges (segments). It enjoys widespread use due to its performance and accuracy. Godot's A* implementation uses points in three-dimensional space and Euclidean distances by default.
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 9720405ffd..7ceb21d22e 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -710,7 +710,7 @@
[b]Note:[/b] Length is not delimited by the last key, as this one may be before or after the end to ensure correct interpolation and looping.
</member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
- A flag indicating that the animation must loop. This is uses for correct interpolation of animation cycles, and for hinting the player that it must restart the animation.
+ A flag indicating that the animation must loop. This is used for correct interpolation of animation cycles, and for hinting the player that it must restart the animation.
</member>
<member name="step" type="float" setter="set_step" getter="get_step" default="0.1">
The animation step value.
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index e5ba1d58f7..7696f36009 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -237,7 +237,7 @@
</member>
<member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation" default="&quot;&quot;">
The name of the currently playing animation. If no animation is playing, the property's value is an empty string. Changing this value does not restart the animation. See [method play] for more information on playing animations.
- [b]Note[/b]: while this property appears in the inspector, it's not meant to be edited and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
+ [b]Note[/b]: while this property appears in the inspector, it's not meant to be edited, and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
</member>
<member name="current_animation_length" type="float" setter="" getter="get_current_animation_length">
The length (in seconds) of the currently being played animation.
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 8fb688a8ae..dcfb91eb61 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -166,7 +166,7 @@
[/codeblock]
</description>
</method>
- <method name="back">
+ <method name="back" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -207,7 +207,7 @@
Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
</description>
</method>
- <method name="count">
+ <method name="count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="value" type="Variant">
@@ -216,7 +216,7 @@
Returns the number of times an element is in the array.
</description>
</method>
- <method name="duplicate">
+ <method name="duplicate" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="deep" type="bool" default="false">
@@ -237,7 +237,7 @@
[b]Note:[/b] On large arrays, this method will be slower if the removed element is close to the beginning of the array (index 0). This is because all elements placed after the removed element have to be reindexed.
</description>
</method>
- <method name="find">
+ <method name="find" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="Variant">
@@ -248,7 +248,7 @@
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
- <method name="find_last">
+ <method name="find_last" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="value" type="Variant">
@@ -257,7 +257,7 @@
Searches the array in reverse order for a value and returns its index or [code]-1[/code] if not found.
</description>
</method>
- <method name="front">
+ <method name="front" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -265,7 +265,7 @@
[b]Note:[/b] Calling this function is not the same as writing [code]array[0][/code]. If the array is empty, accessing by index will pause project execution when running from the editor.
</description>
</method>
- <method name="has">
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="value" type="Variant">
@@ -307,7 +307,7 @@
[/codeblocks]
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
@@ -335,21 +335,21 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the array is empty.
</description>
</method>
- <method name="max">
+ <method name="max" qualifiers="const">
<return type="Variant">
</return>
<description>
Returns the maximum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
</description>
</method>
- <method name="min">
+ <method name="min" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -474,7 +474,7 @@
Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are [code]null[/code].
</description>
</method>
- <method name="rfind">
+ <method name="rfind" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="Variant">
@@ -492,14 +492,14 @@
Shuffles the array such that the items will have a random order. This method uses the global random number generator common to methods such as [method @GlobalScope.randi]. Call [method @GlobalScope.randomize] to ensure that a new seed will be used each time if you want non-reproducible shuffling.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
Returns the number of elements in the array.
</description>
</method>
- <method name="slice">
+ <method name="slice" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="begin" type="int">
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 5bc077ef49..9865319419 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AtlasTexture" inherits="Texture2D" version="4.0">
<brief_description>
- Packs multiple small textures in a single, bigger one. Helps to optimize video memory costs and render calls.
+ Crops out one part of a texture, such as a texture from a texture atlas.
</brief_description>
<description>
- [Texture2D] resource aimed at managing big textures files that pack multiple smaller textures. Consists of a [Texture2D], a margin that defines the border width, and a region that defines the actual area of the AtlasTexture.
+ [Texture2D] resource that crops out one part of the [member atlas] texture, defined by [member region]. The main use case is cropping out textures from a texture atlas, which is a big texture file that packs multiple smaller textures. Consists of a [Texture2D] for the [member atlas], a [member region] that defines the area of [member atlas] to use, and a [member margin] that defines the border width.
+ [AtlasTexture] cannot be used in an [AnimatedTexture], cannot be tiled in nodes such as [TextureRect], and does not work properly if used inside of other [AtlasTexture] resources. Multiple [AtlasTexture] resources can be used to crop multiple textures from the atlas. Using a texture atlas helps to optimize video memory costs and render calls compared to using multiple small files.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index cf3d87c2e4..c7ee621ca6 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -67,7 +67,7 @@
</methods>
<members>
<member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="0.1">
- Length of the internal ring buffer, in seconds.
+ Length of the internal ring buffer, in seconds. Setting the buffer length will have no effect if already initialized.
</member>
</members>
<constants>
diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml
index 7cc6a5613b..9a70b8f20c 100644
--- a/doc/classes/BackBufferCopy.xml
+++ b/doc/classes/BackBufferCopy.xml
@@ -4,7 +4,7 @@
Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts through the [code]texture(SCREEN_TEXTURE, ...)[/code] function.
</brief_description>
<description>
- Node for back-buffering the currently-displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer.
+ Node for back-buffering the currently-displayed screen. The region defined in the BackBufferCopy node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer.
[b]Note:[/b] Since this node inherits from [Node2D] (and not [Control]), anchors and margins won't apply to child [Control]-derived nodes. This can be problematic when resizing the window. To avoid this, add [Control]-derived nodes as [i]siblings[/i] to the BackBufferCopy node instead of adding them as children.
</description>
<tutorials>
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index fa0c3b167a..c87398ac8f 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -82,7 +82,7 @@
Texture to multiply by [member albedo_color]. Used for basic texturing of objects.
</member>
<member name="alpha_antialiasing_edge" type="float" setter="set_alpha_antialiasing_edge" getter="get_alpha_antialiasing_edge">
- Threshold at which antialiasing will by applied on the alpha channel.
+ Threshold at which antialiasing will be applied on the alpha channel.
</member>
<member name="alpha_antialiasing_mode" type="int" setter="set_alpha_antialiasing" getter="get_alpha_antialiasing" enum="BaseMaterial3D.AlphaAntiAliasing">
The type of alpha antialiasing to apply. See [enum AlphaAntiAliasing].
@@ -127,7 +127,7 @@
Texture used to control the backlight effect per-pixel. Added to [member backlight].
</member>
<member name="billboard_keep_scale" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
+ If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise, the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
</member>
<member name="billboard_mode" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0">
Controls how the object faces the camera. See [enum BillboardMode].
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 4c9cd5702e..55ae58ee3a 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -78,7 +78,7 @@
Constructs a basis matrix from 3 axis vectors (matrix columns).
</description>
</method>
- <method name="determinant">
+ <method name="determinant" qualifiers="const">
<return type="float">
</return>
<description>
@@ -86,7 +86,7 @@
A negative determinant means the basis has a negative scale. A zero determinant means the basis isn't invertible, and is usually considered invalid.
</description>
</method>
- <method name="get_euler">
+ <method name="get_euler" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -94,35 +94,35 @@
Consider using the [method get_rotation_quat] method instead, which returns a [Quat] quaternion instead of Euler angles.
</description>
</method>
- <method name="get_orthogonal_index">
+ <method name="get_orthogonal_index" qualifiers="const">
<return type="int">
</return>
<description>
This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code.
</description>
</method>
- <method name="get_rotation_quat">
+ <method name="get_rotation_quat" qualifiers="const">
<return type="Quat">
</return>
<description>
Returns the basis's rotation in the form of a quaternion. See [method get_euler] if you need Euler angles, but keep in mind quaternions should generally be preferred to Euler angles.
</description>
</method>
- <method name="get_scale">
+ <method name="get_scale" qualifiers="const">
<return type="Vector3">
</return>
<description>
Assuming that the matrix is the combination of a rotation and scaling, return the absolute value of scaling factors along each axis.
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Basis">
</return>
<description>
Returns the inverse of the matrix.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Basis">
@@ -171,14 +171,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Basis">
</return>
<description>
Returns the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error for orthogonal matrices). This performs a Gram-Schmidt orthonormalization on the basis of the matrix.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -189,7 +189,7 @@
Introduce an additional rotation around the given axis by phi (radians). The axis must be a normalized vector.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -198,7 +198,7 @@
Introduce an additional scaling specified by the given 3D scaling factor.
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="to" type="Basis">
@@ -209,7 +209,7 @@
Assuming that the matrix is a proper rotation matrix, slerp performs a spherical-linear interpolation with another rotation matrix.
</description>
</method>
- <method name="tdotx">
+ <method name="tdotx" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -218,7 +218,7 @@
Transposed dot product with the X axis of the matrix.
</description>
</method>
- <method name="tdoty">
+ <method name="tdoty" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -227,7 +227,7 @@
Transposed dot product with the Y axis of the matrix.
</description>
</method>
- <method name="tdotz">
+ <method name="tdotz" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -236,7 +236,7 @@
Transposed dot product with the Z axis of the matrix.
</description>
</method>
- <method name="transposed">
+ <method name="transposed" qualifiers="const">
<return type="Basis">
</return>
<description>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index b69768d33f..0cfbd0270c 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -63,70 +63,70 @@
Creates a new [Callable] for the method called [code]method[/code] in the specified [code]object[/code].
</description>
</method>
- <method name="bind" qualifiers="vararg">
+ <method name="bind" qualifiers="vararg const">
<return type="Callable">
</return>
<description>
Returns a copy of this [Callable] with the arguments bound. Bound arguments are passed after the arguments supplied by [method call].
</description>
</method>
- <method name="call" qualifiers="vararg">
+ <method name="call" qualifiers="vararg const">
<return type="Variant">
</return>
<description>
Calls the method represented by this [Callable]. Arguments can be passed and should match the method's signature.
</description>
</method>
- <method name="call_deferred" qualifiers="vararg">
+ <method name="call_deferred" qualifiers="vararg const">
<return type="void">
</return>
<description>
Calls the method represented by this [Callable] in deferred mode, i.e. during the idle frame. Arguments can be passed and should match the method's signature.
</description>
</method>
- <method name="get_method">
+ <method name="get_method" qualifiers="const">
<return type="StringName">
</return>
<description>
Returns the name of the method represented by this [Callable].
</description>
</method>
- <method name="get_object">
+ <method name="get_object" qualifiers="const">
<return type="Object">
</return>
<description>
Returns the object on which this [Callable] is called.
</description>
</method>
- <method name="get_object_id">
+ <method name="get_object_id" qualifiers="const">
<return type="int">
</return>
<description>
Returns the ID of this [Callable]'s object (see [method Object.get_instance_id]).
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
Returns the hash value of this [Callable]'s object.
</description>
</method>
- <method name="is_custom">
+ <method name="is_custom" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this [Callable] is a custom callable whose behavior differs based on implementation details. Custom callables are used in the engine for various reasons. If [code]true[/code], you can't use [method get_method].
</description>
</method>
- <method name="is_null">
+ <method name="is_null" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this [Callable] has no target to call the method on.
</description>
</method>
- <method name="is_standard">
+ <method name="is_standard" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -151,7 +151,7 @@
Returns [code]true[/code] if both [Callable]s invoke the same custom target.
</description>
</method>
- <method name="unbind">
+ <method name="unbind" qualifiers="const">
<return type="Callable">
</return>
<argument index="0" name="argcount" type="int">
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 034b2e9629..9f1d6d8e31 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -194,7 +194,7 @@
</member>
<member name="fov" type="float" setter="set_fov" getter="get_fov" default="75.0">
The camera's field of view angle (in degrees). Only applicable in perspective mode. Since [member keep_aspect] locks one axis, [code]fov[/code] sets the other axis' field of view angle.
- For reference, the default vertical field of view value ([code]75.0[/code]) is equivalent to an horizontal FOV of:
+ For reference, the default vertical field of view value ([code]75.0[/code]) is equivalent to a horizontal FOV of:
- ~91.31 degrees in a 4:3 viewport
- ~101.67 degrees in a 16:10 viewport
- ~107.51 degrees in a 16:9 viewport
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index d13f431a16..87b157db4e 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -318,7 +318,7 @@
<argument index="9" name="flags" type="int" default="3">
</argument>
<description>
- Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
[b]Example using the default project font:[/b]
[codeblocks]
[gdscript]
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index d1483ac88e..81795abcdd 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -3,7 +3,7 @@
<brief_description>
</brief_description>
<description>
- [b]Note[/b]: By default [CodeEdit] always use left-to-right text direction to correcly display source code.
+ [b]Note[/b]: By default [CodeEdit] always use left-to-right text direction to correctly display source code.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index ce88e0ae88..c33d007735 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -56,10 +56,8 @@
</return>
<argument index="0" name="code" type="String">
</argument>
- <argument index="1" name="alpha" type="float">
- </argument>
<description>
- Constructs a [Color] either from an HTML color code or from a standardized color name, with [code]alpha[/code] on the range of 0 to 1. Supported color names are the same as the constants.
+ Constructs a [Color] either from an HTML color code or from a standardized color name. Supported color names are the same as the constants.
</description>
</method>
<method name="Color" qualifiers="constructor">
@@ -67,8 +65,10 @@
</return>
<argument index="0" name="code" type="String">
</argument>
+ <argument index="1" name="alpha" type="float">
+ </argument>
<description>
- Constructs a [Color] either from an HTML color code or from a standardized color name. Supported color names are the same as the constants.
+ Constructs a [Color] either from an HTML color code or from a standardized color name, with [code]alpha[/code] on the range of 0 to 1. Supported color names are the same as the constants.
</description>
</method>
<method name="Color" qualifiers="constructor">
@@ -80,16 +80,14 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
- <argument index="3" name="a" type="float">
- </argument>
<description>
- Constructs a [Color] from RGBA values, typically between 0 and 1.
+ Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
[codeblocks]
[gdscript]
- var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
+ var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
[/gdscript]
[csharp]
- var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
+ var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
[/csharp]
[/codeblocks]
</description>
@@ -103,19 +101,21 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
+ <argument index="3" name="a" type="float">
+ </argument>
<description>
- Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
+ Constructs a [Color] from RGBA values, typically between 0 and 1.
[codeblocks]
[gdscript]
- var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
+ var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
[/gdscript]
[csharp]
- var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
+ var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
[/csharp]
[/codeblocks]
</description>
</method>
- <method name="blend">
+ <method name="blend" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="over" type="Color">
@@ -136,7 +136,7 @@
[/codeblocks]
</description>
</method>
- <method name="darkened">
+ <method name="darkened" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="amount" type="float">
@@ -155,7 +155,87 @@
[/codeblocks]
</description>
</method>
- <method name="inverted">
+ <method name="find_named_color" qualifiers="static">
+ <return type="int">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="from_rgbe9995" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="rgbe" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="from_string" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="str" type="String">
+ </argument>
+ <argument index="1" name="default" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color_count" qualifiers="static">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color_name" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hex" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="hex" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hex64" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="hex" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="html" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="rgba" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="html_is_valid" qualifiers="static">
+ <return type="bool">
+ </return>
+ <argument index="0" name="color" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="inverted" qualifiers="const">
<return type="Color">
</return>
<description>
@@ -172,7 +252,7 @@
[/codeblocks]
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Color">
@@ -181,7 +261,7 @@
Returns [code]true[/code] if this color and [code]color[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="to" type="Color">
@@ -204,7 +284,7 @@
[/codeblocks]
</description>
</method>
- <method name="lightened">
+ <method name="lightened" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="amount" type="float">
@@ -323,7 +403,7 @@
<description>
</description>
</method>
- <method name="to_abgr32">
+ <method name="to_abgr32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -340,7 +420,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_abgr64">
+ <method name="to_abgr64" qualifiers="const">
<return type="int">
</return>
<description>
@@ -357,7 +437,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_argb32">
+ <method name="to_argb32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -374,7 +454,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_argb64">
+ <method name="to_argb64" qualifiers="const">
<return type="int">
</return>
<description>
@@ -391,7 +471,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_html">
+ <method name="to_html" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="with_alpha" type="bool" default="true">
@@ -413,7 +493,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_rgba32">
+ <method name="to_rgba32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -430,7 +510,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_rgba64">
+ <method name="to_rgba64" qualifiers="const">
<return type="int">
</return>
<description>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index 3e83202472..a9687abedc 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -28,6 +28,11 @@
</description>
</method>
</methods>
+ <members>
+ <member name="backface_collision" type="bool" setter="set_backface_collision_enabled" getter="is_backface_collision_enabled" default="false">
+ If set to [code]true[/code], collisions occur on both sides of the concave shape faces. Otherwise they occur only along the face normals.
+ </member>
+ </members>
<constants>
</constants>
</class>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index da17d993e3..2cac424f2e 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -158,7 +158,7 @@
<argument index="0" name="data" type="String">
</argument>
<description>
- Parses the the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on.
+ Parses the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index 410c2262f9..26b3087b21 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -27,7 +27,7 @@
</argument>
<description>
Loads a key from [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be loaded.
- [b]Note[/b]: [code]path[/code] should should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ [b]Note[/b]: [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="load_from_string">
@@ -50,7 +50,7 @@
</argument>
<description>
Saves a key to the given [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be saved.
- [b]Note[/b]: [code]path[/code] should should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ [b]Note[/b]: [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="save_to_string">
diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml
index ca36b2400c..14c35ae6d3 100644
--- a/doc/classes/Decal.xml
+++ b/doc/classes/Decal.xml
@@ -6,7 +6,7 @@
<description>
[Decal]s are used to project a texture onto a [Mesh] in the scene. Use Decals to add detail to a scene without affecting the underlying [Mesh]. They are often used to add weathering to building, add dirt or mud to the ground, or add variety to props. Decals can be moved at any time, making them suitable for things like blob shadows or laser sight dots.
They are made of an [AABB] and a group of [Texture2D]s specifying [Color], normal, ORM (ambient occlusion, roughness, metallic), and emission. Decals are projected within their [AABB] so altering the orientation of the Decal affects the direction in which they are projected. By default, Decals are projected down (i.e. from positive Y to negative Y).
- The [Texture2D]s associated with the Decal are automatically stored in a texture atlas which is used for drawing the decals so all decals can be drawn at once. Godot uses clustered decals, meaning they are stored in cluster data and drawn when the mesh is drawn, they are not drawn as a postprocessing effect after.
+ The [Texture2D]s associated with the Decal are automatically stored in a texture atlas which is used for drawing the decals so all decals can be drawn at once. Godot uses clustered decals, meaning they are stored in cluster data and drawn when the mesh is drawn, they are not drawn as a post-processing effect after.
</description>
<tutorials>
</tutorials>
@@ -65,7 +65,7 @@
Blends the albedo [Color] of the decal with albedo [Color] of the underlying mesh.
</member>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
- Specifies which [member VisualInstance3D.layers] this decal will project on. By default, Decals affect all layers. This is used so you can specify which types of objects receive the Decal and which do not. This is especially useful so you an ensure that dynamic objects don't accidentally receive a Decal intended for the terrain under them.
+ Specifies which [member VisualInstance3D.layers] this decal will project on. By default, Decals affect all layers. This is used so you can specify which types of objects receive the Decal and which do not. This is especially useful so you can ensure that dynamic objects don't accidentally receive a Decal intended for the terrain under them.
</member>
<member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="10.0">
Distance from the camera at which the Decal begins to fade away.
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index d3fcbc9f64..16c4348994 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -4,7 +4,7 @@
Dictionary type.
</brief_description>
<description>
- Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as an hash map or associative array.
+ Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
[b]Note:[/b] Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use [method duplicate].
@@ -206,7 +206,7 @@
Clear the dictionary, removing all key/value pairs.
</description>
</method>
- <method name="duplicate">
+ <method name="duplicate" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="deep" type="bool" default="false">
@@ -224,7 +224,7 @@
Erase a dictionary key/value pair by key. Returns [code]true[/code] if the given key was present in the dictionary, [code]false[/code] otherwise. Does not erase elements while iterating over the dictionary.
</description>
</method>
- <method name="get">
+ <method name="get" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="key" type="Variant">
@@ -235,7 +235,7 @@
Returns the current value for the specified key in the [Dictionary]. If the key does not exist, the method returns the value of the optional default argument, or [code]null[/code] if it is omitted.
</description>
</method>
- <method name="has">
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="key" type="Variant">
@@ -260,16 +260,16 @@
This method (like the [code]in[/code] operator) will evaluate to [code]true[/code] as long as the key exists, even if the associated value is [code]null[/code].
</description>
</method>
- <method name="has_all">
+ <method name="has_all" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="keys" type="Array">
</argument>
<description>
- Returns [code]true[/code] if the dictionary has all of the keys in the given array.
+ Returns [code]true[/code] if the dictionary has all the keys in the given array.
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
@@ -292,14 +292,14 @@
[b]Note:[/b] Dictionaries with the same keys/values but in a different order will have a different hash.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the dictionary is empty.
</description>
</method>
- <method name="keys">
+ <method name="keys" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -330,14 +330,14 @@
<description>
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
Returns the number of keys in the dictionary.
</description>
</method>
- <method name="values">
+ <method name="values" qualifiers="const">
<return type="Array">
</return>
<description>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index 2d7292717d..6a126204c6 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -125,7 +125,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). On other platforms, or if the requested drive does not existed, the method returns an empty String.
+ On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). On other platforms, or if the requested drive does not exist, the method returns an empty String.
</description>
</method>
<method name="get_drive_count">
@@ -167,7 +167,7 @@
<return type="void">
</return>
<description>
- Closes the current stream opened with [method list_dir_begin] (whether it has been fully processed with [method get_next] or not does not matter).
+ Closes the current stream opened with [method list_dir_begin] (whether it has been fully processed with [method get_next] does not matter).
</description>
</method>
<method name="make_dir">
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index 5461dccd27..3a045817c2 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -90,7 +90,7 @@
<argument index="0" name="resources" type="PackedStringArray">
</argument>
<description>
- Remitted if a resource is reimported.
+ Emitted if a resource is reimported.
</description>
</signal>
<signal name="resources_reload">
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index 3cc624f49b..8204dc931e 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -4,12 +4,12 @@
Plugin for adding custom property editors on inspector.
</brief_description>
<description>
- This plugins allows adding custom property editors to [EditorInspector].
+ These plugins allow adding custom property editors to [EditorInspector].
Plugins are registered via [method EditorPlugin.add_inspector_plugin].
When an object is edited, the [method can_handle] function is called and must return [code]true[/code] if the object type is supported.
If supported, the function [method parse_begin] will be called, allowing to place custom controls at the beginning of the class.
Subsequently, the [method parse_category] and [method parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too.
- Finally [method parse_end] will be called.
+ Finally, [method parse_end] will be called.
On each of these calls, the "add" functions can be called.
</description>
<tutorials>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 1e9d089962..34657a1c08 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -170,7 +170,7 @@
<return type="bool">
</return>
<description>
- Override this method to define whether Node3D with this gizmo should be selecteble even when the gizmo is hidden.
+ Override this method to define whether Node3D with this gizmo should be selectable even when the gizmo is hidden.
</description>
</method>
<method name="redraw" qualifiers="virtual">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index a24e4bbdc5..8dcffb0b74 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -561,7 +561,7 @@
<argument index="0" name="script" type="Script">
</argument>
<description>
- Removes the debugger plugin with given script fromm the Debugger.
+ Removes the debugger plugin with given script from the Debugger.
</description>
</method>
<method name="remove_export_plugin">
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index bb356c2183..0056b5ce16 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -38,7 +38,7 @@
<return type="Dictionary">
</return>
<description>
- Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of a change the corresponding file has experienced.
+ Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of change the corresponding file has experienced.
The following integer values are being used to signify that the detected file is:
- [code]0[/code]: New to the VCS working directory
- [code]1[/code]: Modified
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 02b81ee9b7..f9d8cf574a 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -162,7 +162,7 @@
The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around tunneling issues, but keep in mind doing so will increase CPU usage.
</member>
<member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5">
- Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows to smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
+ Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
</member>
<member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0">
The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit.
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index 409e405551..20d5b6ce9b 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -175,7 +175,7 @@
</argument>
<description>
Returns the size of a character, optionally taking kerning into account if the next character is provided.
- [b]Note:[/b] Do not use this function to calculate width of the string character by character, use [method get_string_size] or [TextLine] instead.
+ [b]Note:[/b] Do not use this function to calculate width of the string character by character, use [method get_string_size] or [TextLine] instead. The height returned is the font height (see also [method get_height]) and has no relation to the glyph height.
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -247,7 +247,8 @@
<argument index="1" name="size" type="int" default="-1">
</argument>
<description>
- Returns the size size of a bounding box of a string, taking kerning and advance into account.
+ Returns the size of a bounding box of a string, taking kerning and advance into account.
+ [b]Note:[/b] Real height of the string is context-dependent and can be significantly different from the value returned by [method get_height].
See also [method draw_string].
</description>
</method>
diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml
index 6c54af05cd..e426c8fb36 100644
--- a/doc/classes/FontData.xml
+++ b/doc/classes/FontData.xml
@@ -391,7 +391,7 @@
If [code]true[/code], distance field hint is enabled.
</member>
<member name="extra_spacing_glyph" type="int" setter="set_spacing" getter="get_spacing" default="0">
- Extra spacing for each glyphs in pixels.
+ Extra spacing for each glyph in pixels.
This can be a negative number to make the distance between glyphs smaller.
</member>
<member name="extra_spacing_space" type="int" setter="set_spacing" getter="get_spacing" default="0">
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index d0b930defb..9f012008e3 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -129,7 +129,7 @@
<argument index="2" name="planes" type="Array">
</argument>
<description>
- Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. If no intersecion is found, an the returned array is empty.
+ Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. Otherwise, returns an empty array.
</description>
</method>
<method name="segment_intersects_cylinder">
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 10afa4c339..b4536c0589 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -88,7 +88,7 @@
</return>
<description>
Gets the [HBoxContainer] that contains the zooming and grid snap controls in the top left of the graph.
- Warning: The intended usage of this function is to allow you to reposition or add your own custom controls to the container. This is an internal control and as such should not be freed. If you wish to hide this or any of it's children use their [member CanvasItem.visible] property instead.
+ Warning: The intended usage of this function is to allow you to reposition or add your own custom controls to the container. This is an internal control and as such should not be freed. If you wish to hide this or any of its children, use their [member CanvasItem.visible] property instead.
</description>
</method>
<method name="is_node_connected">
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 279c4c4c94..aae3126c0f 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -6,7 +6,7 @@
<description>
A GraphNode is a container. Each GraphNode can have several input and output slots, sometimes referred to as ports, allowing connections between GraphNodes. To add a slot to GraphNode, add any [Control]-derived child node to it.
After adding at least one child to GraphNode new sections will be automatically created in the Inspector called 'Slot'. When 'Slot' is expanded you will see list with index number for each slot. You can click on each of them to expand further.
- In the Inspector you can enable (show) or disable (hide) slots. By default all slots are disabled so you may not see any slots on your GraphNode initially. You can assign a type to each slot. Only slots of the same type will be able to connect to each other. You can also assign colors to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input connections are on the left and output connections are on the right side of GraphNode. Only enabled slots are counted as connections.
+ In the Inspector you can enable (show) or disable (hide) slots. By default, all slots are disabled so you may not see any slots on your GraphNode initially. You can assign a type to each slot. Only slots of the same type will be able to connect to each other. You can also assign colors to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input connections are on the left and output connections are on the right side of GraphNode. Only enabled slots are counted as connections.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 9ff682f79d..ddfcdf7724 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -4,7 +4,7 @@
Low-level hyper-text transfer protocol client.
</brief_description>
<description>
- Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for an higher-level alternative.[/b]
+ Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for a higher-level alternative.[/b]
[b]Note:[/b] This client only needs to connect to a host once (see [method connect_to_host]) to send multiple requests. Because of this, methods that take URLs usually take just the part after the host instead of the full URL, as the client is already connected to a host. See [method request] for a full example and to get started.
A [HTTPClient] should be reused between multiple requests or to connect to different hosts instead of creating one client per request. Supports SSL and SSL server certificate verification. HTTP status codes in the 2xx range indicate success, 3xx redirection (i.e. "try again, but over here"), 4xx something was wrong with the request, and 5xx something went wrong on the server's side.
For more information on HTTP, see https://developer.mozilla.org/en-US/docs/Web/HTTP (or read RFC 2616 to get it straight from the source: https://tools.ietf.org/html/rfc2616).
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index a65f66c72a..25667d8f79 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -229,7 +229,7 @@
<member name="accept_gzip" type="bool" setter="set_accept_gzip" getter="is_accepting_gzip" default="true">
If [code]true[/code], this header will be added to each request: [code]Accept-Encoding: gzip, deflate[/code] telling servers that it's okay to compress response bodies.
Any Response body declaring a [code]Content-Encoding[/code] of either [code]gzip[/code] or [code]deflate[/code] will then be automatically decompressed, and the uncompressed bytes will be delivered via [code]request_completed[/code].
- If the user has specified their own [code]Accept-Encoding[/code] header, then no header will be added regaurdless of [code]accept_gzip[/code].
+ If the user has specified their own [code]Accept-Encoding[/code] header, then no header will be added regardless of [code]accept_gzip[/code].
If [code]false[/code] no header will be added, and no decompression will be performed on response bodies. The raw bytes of the response body will be returned via [code]request_completed[/code].
</member>
<member name="body_size_limit" type="int" setter="set_body_size_limit" getter="get_body_size_limit" default="-1">
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 152f381a83..849f036bbd 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -31,7 +31,7 @@
<return type="Array">
</return>
<description>
- Returns all of the user's current IPv4 and IPv6 addresses as an array.
+ Returns all the user's current IPv4 and IPv6 addresses as an array.
</description>
</method>
<method name="get_local_interfaces" qualifiers="const">
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index bad8127c03..9d87c9bf9a 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -240,7 +240,7 @@
<argument index="0" name="renormalize" type="bool" default="false">
</argument>
<description>
- Generates mipmaps for the image. Mipmaps are pre-calculated and lower resolution copies of the image. Mipmaps are automatically used if the image needs to be scaled down when rendered. This improves image quality and the performance of the rendering. Returns an error if the image is compressed, in a custom format or if the image's width/height is 0.
+ Generates mipmaps for the image. Mipmaps are precalculated and lower resolution copies of the image. Mipmaps are automatically used if the image needs to be scaled down when rendered. This improves image quality and the performance of the rendering. Returns an error if the image is compressed, in a custom format or if the image's width/height is 0.
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -560,7 +560,7 @@
</methods>
<members>
<member name="data" type="Dictionary" setter="_set_data" getter="_get_data" default="{&quot;data&quot;: PackedByteArray( ),&quot;format&quot;: &quot;Lum8&quot;,&quot;height&quot;: 0,&quot;mipmaps&quot;: false,&quot;width&quot;: 0}">
- Holds all of the image's color data in a given format. See [enum Format] constants.
+ Holds all the image's color data in a given format. See [enum Format] constants.
</member>
</members>
<constants>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 1f872db6c6..659d791ccf 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -49,7 +49,7 @@
<return type="Vector3">
</return>
<description>
- Returns the acceleration of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the acceleration in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
@@ -85,7 +85,7 @@
</argument>
<description>
Get axis input by specifying two actions, one negative and one positive.
- This is a horthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
+ This is a shorthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
</description>
</method>
<method name="get_connected_joypads">
@@ -106,7 +106,7 @@
<return type="Vector3">
</return>
<description>
- Returns the gravity of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the gravity in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
@@ -176,7 +176,7 @@
<return type="Vector3">
</return>
<description>
- Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 1fe85a5ae8..ed290fc7e2 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -21,7 +21,7 @@
If [code]true[/code], the action's state is pressed. If [code]false[/code], the action's state is released.
</member>
<member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
- The action's strength between 0 and 1. This value is considered as equal to 0 if pressed is [code]false[/code]. The event strength allows faking analog joypad motion events, by precising how strongly is the joypad axis bent or pressed.
+ The action's strength between 0 and 1. This value is considered as equal to 0 if pressed is [code]false[/code]. The event strength allows faking analog joypad motion events, by specifying how strongly the joypad axis is bent or pressed.
</member>
</members>
<constants>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index 8574ff9836..76b9686393 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -32,7 +32,7 @@
</argument>
<description>
Returns the height of the line [code]line[/code].
- If [code]line[/code] is set to [code]-1[/code], returns biggest line height.
+ If [code]line[/code] is set to [code]-1[/code], returns the biggest line height.
If there're no lines returns font size in pixels.
</description>
</method>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 111473e098..6bae612c9f 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -58,7 +58,7 @@
If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
</member>
<member name="light_projector" type="Texture2D" setter="set_projector" getter="get_projector">
- [Texture2D] projected by light. [member shadow_enabled] must be on for the projector to work. Light projectors make the light appear as if it is shining through a colored but transparent object, almost like light shining through stained glass.
+ [Texture2D] projected by light. [member shadow_enabled] must be on for the projector to work. Light projectors make the light appear as if it is shining through a colored but transparent object, almost like light shining through stained-glass.
</member>
<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s. Increasing this value will make the light fade out slower and shadows appear blurrier. This can be used to simulate area lights to an extent.
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 481b737eee..7cbf9d3dfe 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Special button that brings up a [PopupMenu] when clicked.
- New items can be created inside this [PopupMenu] using [code]get_popup().add_item("My Item Name")[/code]. You can also create them directly from the editor. To do so, select the [MenuButton] node, then in the toolbar at the top of the 2D editor, click [b]Items[/b] then click [b]Add[/b] in the popup. You will be able to give each items new properties.
+ New items can be created inside this [PopupMenu] using [code]get_popup().add_item("My Item Name")[/code]. You can also create them directly from the editor. To do so, select the [MenuButton] node, then in the toolbar at the top of the 2D editor, click [b]Items[/b] then click [b]Add[/b] in the popup. You will be able to give each item new properties.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 6ebfc946dc..2adebdb306 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -6,7 +6,7 @@
<description>
MultiMesh provides low-level mesh instancing. Drawing thousands of [MeshInstance3D] nodes can be slow, since each object is submitted to the GPU then drawn individually.
MultiMesh is much faster as it can draw thousands of instances with a single draw call, resulting in less API overhead.
- As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always rendered (they are spatially indexed as one, for the whole object).
+ As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always render (they are spatially indexed as one, for the whole object).
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
</description>
<tutorials>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 59bf06eaf2..1060e2de41 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -111,7 +111,7 @@
The distance threshold before a target is considered to be reached. This will allow an agent to not have to hit a point on the path exactly, but in the area.
</member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="20.0">
- The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithim, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
+ The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
</members>
<signals>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 7a130e9591..00e9db0a33 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -117,7 +117,7 @@
The distance threshold before a target is considered to be reached. This will allow an agent to not have to hit a point on the path exactly, but in the area.
</member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="5.0">
- The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithim, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
+ The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
</members>
<signals>
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index dd7464ac0e..1f6e582731 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -111,7 +111,7 @@
The physics layers used to generate the [NavigationMesh].
</member>
<member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" default="0">
- What kind of geomerty is used to generate the [NavigationMesh].
+ What kind of geometry is used to generate the [NavigationMesh].
</member>
<member name="geometry/source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" default="0">
Which geometry is used to generate the [NavigationMesh].
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 4f34a8a424..b0a57ed227 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
NavigationServer2D is the server responsible for all 2D navigation. It handles several objects, namely maps, regions and agents.
- Maps are made up of regions, which are made of navigation polygons. Together, they define the navigable areas in the 2D world. For two regions to be connected to each other, they must share a similar edge. An edges is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ Maps are made up of regions, which are made of navigation polygons. Together, they define the navigable areas in the 2D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
You may assign navigation layers to regions with [method NavigationServer2D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer2D.map_get_path]. This allows allowing or forbidding some areas to 2D objects.
To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
[b]Note:[/b] the collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
@@ -267,6 +267,37 @@
Creates a new region.
</description>
</method>
+ <method name="region_get_connection_pathway_end" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connection_pathway_start" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connections_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns how many connections this [code]region[/code] has with other regions in the map.
+ </description>
+ </method>
<method name="region_get_layers" qualifiers="const">
<return type="int">
</return>
@@ -321,6 +352,15 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="map_changed">
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Emitted when a navigation map is updated, when a region moves or is modified.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 0653c0d27d..b098a7fc20 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
NavigationServer3D is the server responsible for all 3D navigation. It handles several objects, namely maps, regions and agents.
- Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world. For two regions to be connected to each other, they must share a similar edge. An edges is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
You may assign navigation layers to regions with [method NavigationServer3D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer3D.map_get_path]. This allows allowing or forbidding some areas to 3D objects.
To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
[b]Note:[/b] the collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
@@ -335,6 +335,37 @@
Creates a new region.
</description>
</method>
+ <method name="region_get_connection_pathway_end" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connection_pathway_start" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connections_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns how many connections this [code]region[/code] has with other regions in the map.
+ </description>
+ </method>
<method name="region_get_layers" qualifiers="const">
<return type="int">
</return>
@@ -398,6 +429,15 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="map_changed">
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Emitted when a navigation map is updated, when a region moves or is modified.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 7ee6860dfc..7750d45226 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -128,7 +128,7 @@
</argument>
<description>
Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have an human-readable name based on the name of the node being instanced instead of its type.
+ If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type.
[b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example:
[codeblocks]
[gdscript]
@@ -158,8 +158,8 @@
<argument index="1" name="legible_unique_name" type="bool" default="false">
</argument>
<description>
- Adds a [code]sibling[/code] node to current's node parent, at the the same level as that node, right below it.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have an human-readable name based on the name of the node being instanced instead of its type.
+ Adds a [code]sibling[/code] node to current's node parent, at the same level as that node, right below it.
+ If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type.
Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children.
</description>
</method>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 36835d9e94..817ccd5160 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -66,11 +66,11 @@
[/codeblock]
</description>
</method>
- <method name="get_as_property_path">
+ <method name="get_as_property_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
- Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the from the current node).
+ Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the current node).
[codeblocks]
[gdscript]
# This will be parsed as a node path to the "x" property in the "position" node.
@@ -89,7 +89,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_concatenated_subnames">
+ <method name="get_concatenated_subnames" qualifiers="const">
<return type="StringName">
</return>
<description>
@@ -106,7 +106,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_name">
+ <method name="get_name" qualifiers="const">
<return type="StringName">
</return>
<argument index="0" name="idx" type="int">
@@ -129,7 +129,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_name_count">
+ <method name="get_name_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -137,7 +137,7 @@
For example, [code]"Path2D/PathFollow2D/Sprite2D"[/code] has 3 names.
</description>
</method>
- <method name="get_subname">
+ <method name="get_subname" qualifiers="const">
<return type="StringName">
</return>
<argument index="0" name="idx" type="int">
@@ -158,7 +158,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_subname_count">
+ <method name="get_subname_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -166,14 +166,14 @@
For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:load_path"[/code] has 2 subnames.
</description>
</method>
- <method name="is_absolute">
+ <method name="is_absolute" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the node path is absolute (as opposed to relative), which means that it starts with a slash character ([code]/[/code]). Absolute node paths can be used to access the root node ([code]"/root"[/code]) or autoloads (e.g. [code]"/global"[/code] if a "global" autoload was registered).
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 548147beab..a76ea5868c 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -244,9 +244,9 @@
</return>
<description>
Returns the host OS locale as a string of the form [code]language_Script_COUNTRY_VARIANT@extra[/code].
- [code]language[/code] - 2 or 3 letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
- [code]Script[/code] - optional, 4 letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
- [code]COUNTRY[/code] - optional, 2 or 3 letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
+ [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
+ [code]Script[/code] - optional, 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
+ [code]COUNTRY[/code] - optional, 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
[code]VARIANT[/code] - optional, language variant, region and sort order. Variant can have any number of underscored key words.
[code]extra[/code] - optional, semicolon separated list of additional key words. Currency, calendar, sort order and numbering system information.
</description>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index ad3ce8e93e..7da9c1ac38 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Object" version="4.0">
<brief_description>
- Base class for all non built-in types.
+ Base class for all non-built-in types.
</brief_description>
<description>
Every class which is not a built-in type inherits from this class.
@@ -179,7 +179,7 @@
</argument>
<description>
Connects a [code]signal[/code] to a [code]callable[/code]. Pass optional [code]binds[/code] to the call as an [Array] of parameters. These parameters will be passed to the [Callable]'s method after any parameter used in the call to [method emit_signal]. Use [code]flags[/code] to set deferred or one-shot connections. See [enum ConnectFlags] constants.
- [b]Note:[/b] This method is the legacy implementation for connecting signals. The recommend modern approach is to use [method Signal.connect] and to use [method Callable.bind] to add and validate parameter binds. Both syntaxes are shown below.
+ [b]Note:[/b] This method is the legacy implementation for connecting signals. The recommended modern approach is to use [method Signal.connect] and to use [method Callable.bind] to add and validate parameter binds. Both syntaxes are shown below.
A signal can only be connected once to a [Callable]. It will throw an error if already connected, unless the signal was connected with [constant CONNECT_REFERENCE_COUNTED]. To avoid this, first, use [method is_connected] to check for existing connections.
If the callable's target is destroyed in the game's lifecycle, the connection will be lost.
[b]Examples with recommended syntax:[/b]
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 75fb7c1465..3c7f0f4fad 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -52,7 +52,7 @@
Appends a [PackedByteArray] at the end of this array.
</description>
</method>
- <method name="compress">
+ <method name="compress" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="compression_mode" type="int" default="0">
@@ -61,7 +61,7 @@
Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
- <method name="decompress">
+ <method name="decompress" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="buffer_size" type="int">
@@ -72,7 +72,7 @@
Returns a new [PackedByteArray] with the data decompressed. Set [code]buffer_size[/code] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
- <method name="decompress_dynamic">
+ <method name="decompress_dynamic" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="max_output_size" type="int">
@@ -81,7 +81,7 @@
</argument>
<description>
Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
- This method is potentially slower than [code]decompress[/code], as it may have to re-allocate it's output buffer multiple times while decompressing, where as [code]decompress[/code] knows it's output buffer size from the beginning.
+ This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning.
GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [code]max_output_size[/code]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
</description>
</method>
@@ -92,28 +92,28 @@
Creates a copy of the array, and returns it.
</description>
</method>
- <method name="get_string_from_ascii">
+ <method name="get_string_from_ascii" qualifiers="const">
<return type="String">
</return>
<description>
Converts ASCII/Latin-1 encoded array to [String]. Fast alternative to [method get_string_from_utf8] if the content is ASCII/Latin-1 only. Unlike the UTF-8 function this function maps every byte to a character in the array. Multibyte sequences will not be interpreted correctly. For parsing user input always use [method get_string_from_utf8].
</description>
</method>
- <method name="get_string_from_utf16">
+ <method name="get_string_from_utf16" qualifiers="const">
<return type="String">
</return>
<description>
Converts UTF-16 encoded array to [String]. If the BOM is missing, system endianness is assumed. Returns empty string if source array is not valid UTF-16 string.
</description>
</method>
- <method name="get_string_from_utf32">
+ <method name="get_string_from_utf32" qualifiers="const">
<return type="String">
</return>
<description>
Converts UTF-32 encoded array to [String]. System endianness is assumed. Returns empty string if source array is not valid UTF-32 string.
</description>
</method>
- <method name="get_string_from_utf8">
+ <method name="get_string_from_utf8" qualifiers="const">
<return type="String">
</return>
<description>
@@ -129,7 +129,7 @@
Returns [code]true[/code] if the array contains [code]value[/code].
</description>
</method>
- <method name="hex_encode">
+ <method name="hex_encode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -164,7 +164,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -241,7 +241,7 @@
Changes the byte at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -255,7 +255,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="from" type="int">
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 48d5822f7c..abfedc84cc 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -86,7 +86,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -163,7 +163,7 @@
Changes the [Color] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -177,7 +177,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedColorArray">
</return>
<argument index="0" name="from" type="int">
@@ -187,7 +187,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 6598828089..8918312dc7 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -156,7 +156,7 @@
Changes the float at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -170,7 +170,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedFloat32Array">
</return>
<argument index="0" name="from" type="int">
@@ -180,7 +180,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index d116c6756b..fbb832299e 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -164,7 +164,7 @@
Changes the float at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +178,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedFloat64Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +188,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index 2ac7a67b4b..ecef2d508b 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -164,7 +164,7 @@
Changes the integer at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +178,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedInt32Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +188,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index a7b6bf0a0f..19619d60cf 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -164,7 +164,7 @@
Changes the integer at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +178,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedInt64Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +188,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index fb7ed2a906..c241573b93 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -164,7 +164,7 @@
Changes the [String] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +178,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +188,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index eb364ddb18..9138dc68e1 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -87,7 +87,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -172,7 +172,7 @@
Changes the [Vector2] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -186,7 +186,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedVector2Array">
</return>
<argument index="0" name="from" type="int">
@@ -196,7 +196,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 08ce187b5c..0a3b0cf2c0 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -86,7 +86,7 @@
Reverses the order of the elements in the array.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -171,7 +171,7 @@
Changes the [Vector3] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -185,7 +185,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedVector3Array">
</return>
<argument index="0" name="from" type="int">
@@ -195,7 +195,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index dcf24c1d32..38d9f722b1 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -91,7 +91,7 @@
The body's bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness).
</member>
<member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
- If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awaken by an external force.
+ If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awakened by an external force.
</member>
<member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0">
The body's friction, from [code]0[/code] (frictionless) to [code]1[/code] (max friction).
diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
index 2e0f9c52f2..381371b973 100644
--- a/doc/classes/PhysicalSkyMaterial.xml
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -23,22 +23,22 @@
Modulates the [Color] on the bottom half of the sky to represent the ground.
</member>
<member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005">
- Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whiteish color around the sun and horizon.
+ Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon.
</member>
<member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color( 0.36, 0.56, 0.82, 1 )">
Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien looking planets.
</member>
<member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8">
- Controls the direction of the mie scattering. A value of [code]1[/code] means that when light hits a particle it passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards.
+ Controls the direction of the mie scattering. A value of [code]1[/code] means that when light hits a particle it's passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards.
</member>
<member name="night_sky" type="Texture2D" setter="set_night_sky" getter="get_night_sky">
[Texture2D] for the night sky. This is added to the sky, so if it is bright enough, it may be visible during the day.
</member>
<member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0">
- Controls the strength of the rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky.
+ Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky.
</member>
<member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color( 0.056, 0.14, 0.3, 1 )">
- Controls the [Color] of the rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a mars looking atmosphere with a corresponding blue sunset.
+ Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a Mars looking atmosphere with a corresponding blue sunset.
</member>
<member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0">
Sets the size of the sun disk. Default value is based on Sol's perceived size from Earth.
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index ed96f753c2..2342f00631 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -76,14 +76,14 @@
Creates a plane from the three points, given in clockwise order.
</description>
</method>
- <method name="center">
+ <method name="center" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the center of the plane.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="point" type="Vector3">
@@ -92,7 +92,7 @@
Returns the shortest distance from the plane to the position [code]point[/code].
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -103,7 +103,7 @@
Returns [code]true[/code] if [code]point[/code] is inside the plane. Comparison uses a custom minimum [code]epsilon[/code] threshold.
</description>
</method>
- <method name="intersect_3">
+ <method name="intersect_3" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="b" type="Plane">
@@ -114,7 +114,7 @@
Returns the intersection point of the three planes [code]b[/code], [code]c[/code] and this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="intersects_ray">
+ <method name="intersects_ray" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -125,7 +125,7 @@
Returns the intersection point of a ray consisting of the position [code]from[/code] and the direction normal [code]dir[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="intersects_segment">
+ <method name="intersects_segment" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -136,7 +136,7 @@
Returns the intersection point of a segment from position [code]begin[/code] to position [code]end[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to_plane" type="Plane">
@@ -145,7 +145,7 @@
Returns [code]true[/code] if this plane and [code]plane[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_point_over">
+ <method name="is_point_over" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="plane" type="Vector3">
@@ -154,7 +154,7 @@
Returns [code]true[/code] if [code]point[/code] is located above the plane.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Plane">
</return>
<description>
@@ -189,7 +189,7 @@
<description>
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="point" type="Vector3">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 51ec509a14..418785222e 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -565,7 +565,7 @@
<argument index="1" name="state" type="int">
</argument>
<description>
- Sets the state of an multistate item. See [method add_multistate_item] for details.
+ Sets the state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
<method name="set_item_opentype_feature">
@@ -664,13 +664,13 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Cycle to the next state of an multistate item. See [method add_multistate_item] for details.
+ Cycle to the next state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
</methods>
<members>
<member name="allow_search" type="bool" setter="set_allow_search" getter="get_allow_search" default="true">
- If [code]true[/code], allows to navigate [PopupMenu] with letter keys.
+ If [code]true[/code], allows navigating [PopupMenu] with letter keys.
</member>
<member name="hide_on_checkable_item_selection" type="bool" setter="set_hide_on_checkable_item_selection" getter="is_hide_on_checkable_item_selection" default="true">
If [code]true[/code], hides the [PopupMenu] when a checkbox or radio button is selected.
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 25943f6d47..8b73bcb9c1 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -31,7 +31,7 @@
</methods>
<members>
<member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )">
- Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unnexpected culling when using a shader to offset vertices.
+ Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices.
</member>
<member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index ac63c5da79..5b9150ab04 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -443,7 +443,7 @@
<member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0">
Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging.
If [member display/window/vsync/use_vsync] is enabled, it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
- This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non real-time rendering of static frames, or test the project under lag conditions.
+ This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions.
</member>
<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
Maximum call stack allowed for debugging GDScript.
@@ -734,7 +734,7 @@
<member name="input_devices/pen_tablet/driver" type="String" setter="" getter="">
Specifies the tablet driver to use. If left empty, the default driver will be used.
</member>
- <member name="input_devices/pen_tablet/driver.windows" type="String" setter="" getter="">
+ <member name="input_devices/pen_tablet/driver.Windows" type="String" setter="" getter="">
Override for [member input_devices/pen_tablet/driver] on Windows.
</member>
<member name="input_devices/pointing/emulate_mouse_from_touch" type="bool" setter="" getter="" default="true">
@@ -1143,7 +1143,7 @@
<member name="navigation/2d/default_cell_size" type="int" setter="" getter="" default="10">
Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size].
</member>
- <member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="100">
+ <member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="5">
Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
</member>
<member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.3">
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index ef83ae7fb9..1c0a3e37c0 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -83,7 +83,7 @@
Constructs a quaternion defined by the given values.
</description>
</method>
- <method name="cubic_slerp">
+ <method name="cubic_slerp" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="b" type="Quat">
@@ -98,7 +98,7 @@
Performs a cubic spherical interpolation between quaternions [code]pre_a[/code], this vector, [code]b[/code], and [code]post_b[/code], by the given amount [code]weight[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Quat">
@@ -107,51 +107,51 @@
Returns the dot product of two quaternions.
</description>
</method>
- <method name="get_euler">
+ <method name="get_euler" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Quat">
</return>
<description>
Returns the inverse of the quaternion.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Quat">
</argument>
<description>
- Returns [code]true[/code] if this quaterion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this quaternion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns whether the quaternion is normalized or not.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length of the quaternion.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length of the quaternion, squared.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Quat">
</return>
<description>
@@ -258,7 +258,7 @@
<description>
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="to" type="Quat">
@@ -270,7 +270,7 @@
[b]Note:[/b] Both quaternions must be normalized.
</description>
</method>
- <method name="slerpni">
+ <method name="slerpni" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="to" type="Quat">
diff --git a/doc/classes/RID.xml b/doc/classes/RID.xml
index 0ee34d4194..e686a4b8fd 100644
--- a/doc/classes/RID.xml
+++ b/doc/classes/RID.xml
@@ -25,7 +25,7 @@
Constructs a [RID] as a copy of the given [RID].
</description>
</method>
- <method name="get_id">
+ <method name="get_id" qualifiers="const">
<return type="int">
</return>
<description>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 5d7ff39587..352a18e326 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -65,14 +65,14 @@
Constructs a [Rect2] by x, y, width, and height.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Rect2">
</return>
<description>
Returns a [Rect2] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
@@ -81,7 +81,7 @@
Returns [code]true[/code] if this [Rect2] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -90,14 +90,14 @@
Returns this [Rect2] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="float">
</return>
<description>
Returns the area of the [Rect2].
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="amount" type="float">
@@ -106,7 +106,7 @@
Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on all sides.
</description>
</method>
- <method name="grow_individual">
+ <method name="grow_individual" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="left" type="float">
@@ -121,7 +121,7 @@
Returns a copy of the [Rect2] grown by the specified amount on each side individually.
</description>
</method>
- <method name="grow_side">
+ <method name="grow_side" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="side" type="int">
@@ -132,14 +132,14 @@
Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [Rect2] is flat or empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
@@ -148,7 +148,7 @@
Returns [code]true[/code] if the [Rect2] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
@@ -158,7 +158,7 @@
If the rectangles do not intersect, an empty [Rect2] is returned.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
@@ -170,7 +170,7 @@
If [code]include_borders[/code] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="rect" type="Rect2">
@@ -179,7 +179,7 @@
Returns [code]true[/code] if this [Rect2] and [code]rect[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
@@ -221,7 +221,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index e581ccdb11..84bef9b406 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -63,14 +63,14 @@
Constructs a [Rect2i] by x, y, width, and height.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Rect2i">
</return>
<description>
Returns a [Rect2i] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -79,7 +79,7 @@
Returns [code]true[/code] if this [Rect2i] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="to" type="Vector2i">
@@ -88,14 +88,14 @@
Returns this [Rect2i] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="int">
</return>
<description>
Returns the area of the [Rect2i].
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="amount" type="int">
@@ -104,7 +104,7 @@
Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on all sides.
</description>
</method>
- <method name="grow_individual">
+ <method name="grow_individual" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="left" type="int">
@@ -119,7 +119,7 @@
Returns a copy of the [Rect2i] grown by the specified amount on each side individually.
</description>
</method>
- <method name="grow_side">
+ <method name="grow_side" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="side" type="int">
@@ -130,14 +130,14 @@
Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [Rect2i] is flat or empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2i">
@@ -146,7 +146,7 @@
Returns [code]true[/code] if the [Rect2i] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -156,7 +156,7 @@
If the rectangles do not intersect, an empty [Rect2i] is returned.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -166,7 +166,7 @@
If [code]include_borders[/code] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -200,7 +200,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector2i" setter="" getter="" default="Vector2i( 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index d2b95fda20..f82301bcf4 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -10,7 +10,7 @@
Resources are created using the [code]*_create[/code] functions.
All objects are drawn to a viewport. You can use the [Viewport] attached to the [SceneTree] or you can create one yourself with [method viewport_create]. When using a custom scenario or canvas, the scenario or canvas needs to be attached to the viewport using [method viewport_set_scenario] or [method viewport_attach_canvas].
In 3D, all visual objects must be associated with a scenario. The scenario is a visual representation of the world. If accessing the rendering server from a running game, the scenario can be accessed from the scene tree from any [Node3D] node with [method Node3D.get_world_3d]. Otherwise, a scenario can be created with [method scenario_create].
- Similarly in 2D, a canvas is needed to draw all canvas items.
+ Similarly, in 2D, a canvas is needed to draw all canvas items.
In 3D, all visible objects are comprised of a resource and an instance. A resource can be a mesh, a particle system, a light, or any other 3D object. In order to be visible resources must be attached to an instance using [method instance_set_base]. The instance must also be attached to the scenario using [method instance_set_scenario] in order to be visible.
In 2D, all visible objects are some form of canvas item. In order to be visible, a canvas item needs to be the child of a canvas attached to a viewport, or it needs to be the child of another canvas item that is eventually attached to the canvas.
</description>
@@ -1292,7 +1292,7 @@
<argument index="1" name="margin" type="float">
</argument>
<description>
- Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
+ Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you to avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
</description>
</method>
<method name="instance_set_layer_mask">
@@ -1520,7 +1520,7 @@
<argument index="1" name="enabled" type="bool">
</argument>
<description>
- If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double sided shadows with [method instance_geometry_set_cast_shadows_setting]. Equivalent to [member Light3D.shadow_reverse_cull_face].
+ If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double-sided shadows with [method instance_geometry_set_cast_shadows_setting]. Equivalent to [member Light3D.shadow_reverse_cull_face].
</description>
</method>
<method name="light_set_shadow">
@@ -2204,7 +2204,7 @@
<argument index="1" name="time" type="float">
</argument>
<description>
- Sets the preprocess time for the particles animation. This lets you delay starting an animation until after the particles have begun emitting. Equivalent to [member GPUParticles3D.preprocess].
+ Sets the preprocess time for the particles' animation. This lets you delay starting an animation until after the particles have begun emitting. Equivalent to [member GPUParticles3D.preprocess].
</description>
</method>
<method name="particles_set_process_material">
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index 2683156ec5..9943f644cf 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -6,7 +6,7 @@
<description>
Godot loads resources in the editor or in exported games using ResourceFormatLoaders. They are queried automatically via the [ResourceLoader] singleton, or when a resource with internal dependencies is loaded. Each file type may load as a different resource type, so multiple ResourceFormatLoaders are registered in the engine.
Extending this class allows you to define your own loader. Be sure to respect the documented return types and values. You should give it a global class name with [code]class_name[/code] for it to be registered. Like built-in ResourceFormatLoaders, it will be called automatically when loading resources of its handled type(s). You may also implement a [ResourceFormatSaver].
- [b]Note:[/b] You can also extend [EditorImportPlugin] if the resource type you need exists but Godot is unable to load its format. Choosing one way over another depends if the format is suitable or not for the final exported game. For example, it's better to import [code].png[/code] textures as [code].stex[/code] ([StreamTexture2D]) first, so they can be loaded with better efficiency on the graphics card.
+ [b]Note:[/b] You can also extend [EditorImportPlugin] if the resource type you need exists but Godot is unable to load its format. Choosing one way over another depends on if the format is suitable or not for the final exported game. For example, it's better to import [code].png[/code] textures as [code].stex[/code] ([StreamTexture2D]) first, so they can be loaded with better efficiency on the graphics card.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 6b27c77f26..ed375a8b1e 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -4,7 +4,7 @@
A body that is controlled by the 2D physics engine.
</brief_description>
<description>
- This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
+ This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
[b]Note:[/b] You should not change a RigidBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index e1f6830eb2..9366d7dd44 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
As one of the most important classes, the [SceneTree] manages the hierarchy of nodes in a scene as well as scenes themselves. Nodes can be added, retrieved and removed. The whole scene tree (and thus the current scene) can be paused. Scenes can be loaded, switched and reloaded.
- You can also use the [SceneTree] to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. a "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once.
+ You can also use the [SceneTree] to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. an "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once.
[SceneTree] is the default [MainLoop] implementation used by scenes, and is thus in charge of the game loop.
</description>
<tutorials>
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index f3e62175c6..f8b749aebf 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -14,7 +14,7 @@
<members>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
The collision margin for the shape. Used in Bullet Physics only.
- Collision margins allows collision detection to be more efficient by adding an extra shell around shapes. Collision algorithms are more expensive when objects overlap by more than their margin, so a higher value for margins is better for performance, at the cost of accuracy around edges as it makes them less sharp.
+ Collision margins allow collision detection to be more efficient by adding an extra shell around shapes. Collision algorithms are more expensive when objects overlap by more than their margin, so a higher value for margins is better for performance, at the cost of accuracy around edges as it makes them less sharp.
</member>
</members>
<constants>
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index b7a2258fc1..84efc974c0 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -57,42 +57,42 @@
Disconnects this signal from the specified [Callable].
</description>
</method>
- <method name="emit" qualifiers="vararg">
+ <method name="emit" qualifiers="vararg const">
<return type="void">
</return>
<description>
Emits this signal to all connected objects.
</description>
</method>
- <method name="get_connections">
+ <method name="get_connections" qualifiers="const">
<return type="Array">
</return>
<description>
Returns the list of [Callable]s connected to this signal.
</description>
</method>
- <method name="get_name">
+ <method name="get_name" qualifiers="const">
<return type="StringName">
</return>
<description>
Returns the name of this signal.
</description>
</method>
- <method name="get_object">
+ <method name="get_object" qualifiers="const">
<return type="Object">
</return>
<description>
Returns the object emitting this signal.
</description>
</method>
- <method name="get_object_id">
+ <method name="get_object_id" qualifiers="const">
<return type="int">
</return>
<description>
Returns the ID of the object emitting this signal (see [method Object.get_instance_id]).
</description>
</method>
- <method name="is_connected">
+ <method name="is_connected" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="callable" type="Callable">
@@ -101,7 +101,7 @@
Returns [code]true[/code] if the specified [Callable] is connected to this signal.
</description>
</method>
- <method name="is_null">
+ <method name="is_null" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index fe2cc1f5ad..cb72ae7e4c 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -297,7 +297,7 @@
<argument index="0" name="bone_idx" type="int">
</argument>
<description>
- Unparents the bone at [code]bone_idx[/code] and sets its rest position to that of it's parent prior to being reset.
+ Unparents the bone at [code]bone_idx[/code] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
<method name="world_transform_to_bone_transform">
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index 04e201e1bd..29f8ecd432 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -77,8 +77,6 @@
</method>
</methods>
<members>
- <member name="angular_stiffness" type="float" setter="set_angular_stiffness" getter="get_angular_stiffness" default="0.0">
- </member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this SoftBody3D is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
@@ -96,8 +94,6 @@
<member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath(&quot;&quot;)">
[NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping.
</member>
- <member name="pose_matching_coefficient" type="float" setter="set_pose_matching_coefficient" getter="get_pose_matching_coefficient" default="0.0">
- </member>
<member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0">
</member>
<member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
@@ -109,8 +105,6 @@
<member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="0.0">
The SoftBody3D's mass.
</member>
- <member name="volume_stiffness" type="float" setter="set_volume_stiffness" getter="get_volume_stiffness" default="0.0">
- </member>
</members>
<constants>
</constants>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index e4df753674..7a949d26e0 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -73,10 +73,10 @@
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
The texture's drawing offset.
</member>
- <member name="region_enabled" type="bool" setter="set_region" getter="is_region" default="false">
+ <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false">
If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect].
</member>
- <member name="region_filter_clip" type="bool" setter="set_region_filter_clip" getter="is_region_filter_clip_enabled" default="false">
+ <member name="region_filter_clip_enabled" type="bool" setter="set_region_filter_clip_enabled" getter="is_region_filter_clip_enabled" default="false">
If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code].
</member>
<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )">
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index f9b947fa3d..658fd1a4f2 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -20,7 +20,7 @@
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
The number of columns in the sprite sheet.
</member>
- <member name="region_enabled" type="bool" setter="set_region" getter="is_region" default="false">
+ <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false">
If [code]true[/code], texture will be cut from a larger atlas texture. See [member region_rect].
</member>
<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )">
diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml
index 078520a095..06b9c2b042 100644
--- a/doc/classes/SpriteBase3D.xml
+++ b/doc/classes/SpriteBase3D.xml
@@ -73,7 +73,7 @@
The texture's drawing offset.
</member>
<member name="opacity" type="float" setter="set_opacity" getter="get_opacity" default="1.0">
- The objects visibility on a scale from [code]0[/code] fully invisible to [code]1[/code] fully visible.
+ The objects' visibility on a scale from [code]0[/code] fully invisible to [code]1[/code] fully visible.
</member>
<member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.01">
The size of one pixel's width on the sprite to scale it in 3D.
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 475b17d395..416438e648 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -44,7 +44,7 @@
Constructs a new String from the given [StringName].
</description>
</method>
- <method name="begins_with">
+ <method name="begins_with" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -53,14 +53,14 @@
Returns [code]true[/code] if the string begins with the given string.
</description>
</method>
- <method name="bigrams">
+ <method name="bigrams" qualifiers="const">
<return type="PackedStringArray">
</return>
<description>
Returns the bigrams (pairs of consecutive letters) of this string.
</description>
</method>
- <method name="bin_to_int">
+ <method name="bin_to_int" qualifiers="const">
<return type="int">
</return>
<description>
@@ -77,14 +77,14 @@
[/codeblocks]
</description>
</method>
- <method name="c_escape">
+ <method name="c_escape" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with special characters escaped using the C language standard.
</description>
</method>
- <method name="c_unescape">
+ <method name="c_unescape" qualifiers="const">
<return type="String">
</return>
<description>
@@ -92,14 +92,14 @@
[b]Note:[/b] Unlike the GDScript parser, this method doesn't support the [code]\uXXXX[/code] escape sequence.
</description>
</method>
- <method name="capitalize">
+ <method name="capitalize" qualifiers="const">
<return type="String">
</return>
<description>
Changes the case of some letters. Replaces underscores with spaces, adds spaces before in-word uppercase characters, converts all letters to lowercase, then capitalizes the first letter and every letter following a space character. For [code]capitalize camelCase mixed_with_underscores[/code], it will return [code]Capitalize Camel Case Mixed With Underscores[/code].
</description>
</method>
- <method name="casecmp_to">
+ <method name="casecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -111,7 +111,15 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
- <method name="count">
+ <method name="chr" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="char" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -124,7 +132,7 @@
Returns the number of occurrences of substring [code]what[/code] between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
</description>
</method>
- <method name="countn">
+ <method name="countn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -137,14 +145,14 @@
Returns the number of occurrences of substring [code]what[/code] (ignoring case) between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
</description>
</method>
- <method name="dedent">
+ <method name="dedent" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with indentation (leading tabs and spaces) removed.
</description>
</method>
- <method name="ends_with">
+ <method name="ends_with" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -153,7 +161,7 @@
Returns [code]true[/code] if the string ends with the given string.
</description>
</method>
- <method name="find">
+ <method name="find" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -174,7 +182,7 @@
[/codeblocks]
</description>
</method>
- <method name="findn">
+ <method name="findn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -185,7 +193,7 @@
Returns the index of the [b]first[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
</description>
</method>
- <method name="format">
+ <method name="format" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="values" type="Variant">
@@ -196,42 +204,42 @@
Formats the string by replacing all occurrences of [code]placeholder[/code] with [code]values[/code].
</description>
</method>
- <method name="get_base_dir">
+ <method name="get_base_dir" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the base directory name.
</description>
</method>
- <method name="get_basename">
+ <method name="get_basename" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the full file path without the extension.
</description>
</method>
- <method name="get_extension">
+ <method name="get_extension" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the extension.
</description>
</method>
- <method name="get_file">
+ <method name="get_file" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the filename.
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
Hashes the string and returns a 32-bit integer.
</description>
</method>
- <method name="hex_to_int">
+ <method name="hex_to_int" qualifiers="const">
<return type="int">
</return>
<description>
@@ -248,7 +256,15 @@
[/codeblocks]
</description>
</method>
- <method name="insert">
+ <method name="humanize_size" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="size" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="insert" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -259,28 +275,28 @@
Returns a copy of the string with the substring [code]what[/code] inserted at the given position.
</description>
</method>
- <method name="is_abs_path">
+ <method name="is_abs_path" qualifiers="const">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, returns [code]true[/code] if the path is absolute.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the length of the string equals [code]0[/code].
</description>
</method>
- <method name="is_rel_path">
+ <method name="is_rel_path" qualifiers="const">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, returns [code]true[/code] if the path is relative.
</description>
</method>
- <method name="is_subsequence_of">
+ <method name="is_subsequence_of" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -289,7 +305,7 @@
Returns [code]true[/code] if this string is a subsequence of the given string.
</description>
</method>
- <method name="is_subsequence_ofi">
+ <method name="is_subsequence_ofi" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -298,7 +314,7 @@
Returns [code]true[/code] if this string is a subsequence of the given string, without considering case.
</description>
</method>
- <method name="is_valid_filename">
+ <method name="is_valid_filename" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -306,14 +322,14 @@
[code]: / \ ? * " | % &lt; &gt;[/code]
</description>
</method>
- <method name="is_valid_float">
+ <method name="is_valid_float" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid float.
</description>
</method>
- <method name="is_valid_hex_number">
+ <method name="is_valid_hex_number" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with_prefix" type="bool" default="false">
@@ -322,35 +338,35 @@
Returns [code]true[/code] if this string contains a valid hexadecimal number. If [code]with_prefix[/code] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
</description>
</method>
- <method name="is_valid_html_color">
+ <method name="is_valid_html_color" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid color in hexadecimal HTML notation. Other HTML notations such as named colors or [code]hsl()[/code] colors aren't considered valid by this method and will return [code]false[/code].
</description>
</method>
- <method name="is_valid_identifier">
+ <method name="is_valid_identifier" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string is a valid identifier. A valid identifier may contain only letters, digits and underscores ([code]_[/code]) and the first character may not be a digit.
</description>
</method>
- <method name="is_valid_integer">
+ <method name="is_valid_integer" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid integer.
</description>
</method>
- <method name="is_valid_ip_address">
+ <method name="is_valid_ip_address" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains only a well-formatted IPv4 or IPv6 address. This method considers [url=https://en.wikipedia.org/wiki/Reserved_IP_addresses]reserved IP addresses[/url] such as [code]0.0.0.0[/code] as valid.
</description>
</method>
- <method name="join">
+ <method name="join" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="parts" type="PackedStringArray">
@@ -368,14 +384,14 @@
[/codeblocks]
</description>
</method>
- <method name="json_escape">
+ <method name="json_escape" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with special characters escaped using the JSON standard.
</description>
</method>
- <method name="left">
+ <method name="left" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -384,14 +400,14 @@
Returns a number of characters from the left of the string.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="int">
</return>
<description>
Returns the string's amount of characters.
</description>
</method>
- <method name="lpad">
+ <method name="lpad" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="min_length" type="int">
@@ -402,7 +418,7 @@
Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the left of the string.
</description>
</method>
- <method name="lstrip">
+ <method name="lstrip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="chars" type="String">
@@ -412,7 +428,7 @@
[b]Note:[/b] The [code]chars[/code] is not a prefix. See [method trim_prefix] method that will remove a single prefix string rather than a set of characters.
</description>
</method>
- <method name="match">
+ <method name="match" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -421,7 +437,7 @@
Does a simple case-sensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]).
</description>
</method>
- <method name="matchn">
+ <method name="matchn" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -430,21 +446,21 @@
Does a simple case-insensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]).
</description>
</method>
- <method name="md5_buffer">
+ <method name="md5_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the MD5 hash of the string as an array of bytes.
</description>
</method>
- <method name="md5_text">
+ <method name="md5_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the MD5 hash of the string as a string.
</description>
</method>
- <method name="naturalnocasecmp_to">
+ <method name="naturalnocasecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -457,7 +473,7 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method casecmp_to].
</description>
</method>
- <method name="nocasecmp_to">
+ <method name="nocasecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -469,6 +485,24 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
+ <method name="num" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="number" type="float">
+ </argument>
+ <argument index="1" name="decimals" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="num_scientific" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="number" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
@@ -549,7 +583,7 @@
<description>
</description>
</method>
- <method name="pad_decimals">
+ <method name="pad_decimals" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -558,7 +592,7 @@
Formats a number to have an exact number of [code]digits[/code] after the decimal point.
</description>
</method>
- <method name="pad_zeros">
+ <method name="pad_zeros" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -567,7 +601,7 @@
Formats a number to have an exact number of [code]digits[/code] before the decimal point.
</description>
</method>
- <method name="plus_file">
+ <method name="plus_file" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="file" type="String">
@@ -576,7 +610,7 @@
If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
</description>
</method>
- <method name="repeat">
+ <method name="repeat" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="count" type="int">
@@ -585,7 +619,7 @@
Returns original string repeated a number of times. The number of repetitions is given by the argument.
</description>
</method>
- <method name="replace">
+ <method name="replace" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -596,7 +630,7 @@
Replaces occurrences of a case-sensitive substring with the given one inside the string.
</description>
</method>
- <method name="replacen">
+ <method name="replacen" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -607,7 +641,7 @@
Replaces occurrences of a case-insensitive substring with the given one inside the string.
</description>
</method>
- <method name="rfind">
+ <method name="rfind" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -618,7 +652,7 @@
Returns the index of the [b]last[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
- <method name="rfindn">
+ <method name="rfindn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -629,7 +663,7 @@
Returns the index of the [b]last[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
- <method name="right">
+ <method name="right" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -638,7 +672,7 @@
Returns the right side of the string from a given position.
</description>
</method>
- <method name="rpad">
+ <method name="rpad" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="min_length" type="int">
@@ -649,7 +683,7 @@
Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the right of the string.
</description>
</method>
- <method name="rsplit">
+ <method name="rsplit" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="delimiter" type="String">
@@ -677,7 +711,7 @@
[/codeblocks]
</description>
</method>
- <method name="rstrip">
+ <method name="rstrip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="chars" type="String">
@@ -687,35 +721,35 @@
[b]Note:[/b] The [code]chars[/code] is not a suffix. See [method trim_suffix] method that will remove a single suffix string rather than a set of characters.
</description>
</method>
- <method name="sha1_buffer">
+ <method name="sha1_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the SHA-1 hash of the string as an array of bytes.
</description>
</method>
- <method name="sha1_text">
+ <method name="sha1_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the SHA-1 hash of the string as a string.
</description>
</method>
- <method name="sha256_buffer">
+ <method name="sha256_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the SHA-256 hash of the string as an array of bytes.
</description>
</method>
- <method name="sha256_text">
+ <method name="sha256_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the SHA-256 hash of the string as a string.
</description>
</method>
- <method name="similarity">
+ <method name="similarity" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="text" type="String">
@@ -724,7 +758,7 @@
Returns the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
</description>
</method>
- <method name="split">
+ <method name="split" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="delimiter" type="String">
@@ -755,7 +789,7 @@
If you need to split strings with more complex rules, use the [RegEx] class instead.
</description>
</method>
- <method name="split_floats">
+ <method name="split_floats" qualifiers="const">
<return type="PackedFloat32Array">
</return>
<argument index="0" name="delimiter" type="String">
@@ -767,7 +801,7 @@
For example, [code]"1,2.5,3"[/code] will return [code][1,2.5,3][/code] if split by [code]","[/code].
</description>
</method>
- <method name="strip_edges">
+ <method name="strip_edges" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="left" type="bool" default="true">
@@ -778,14 +812,14 @@
Returns a copy of the string stripped of any non-printable character (including tabulations, spaces and line breaks) at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
</description>
</method>
- <method name="strip_escapes">
+ <method name="strip_escapes" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string stripped of any escape character. These include all non-printable control characters of the first page of the ASCII table (&lt; 32), such as tabulation ([code]\t[/code] in C) and newline ([code]\n[/code] and [code]\r[/code]) characters, but not spaces.
</description>
</method>
- <method name="substr">
+ <method name="substr" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="from" type="int">
@@ -796,63 +830,63 @@
Returns part of the string from the position [code]from[/code] with length [code]len[/code]. Argument [code]len[/code] is optional and using [code]-1[/code] will return remaining characters from given position.
</description>
</method>
- <method name="to_ascii_buffer">
+ <method name="to_ascii_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is a character array) to ASCII/Latin-1 encoded [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8_buffer], as this method assumes that all the characters in the String are ASCII/Latin-1 characters, unsupported characters are replaced with spaces.
</description>
</method>
- <method name="to_float">
+ <method name="to_float" qualifiers="const">
<return type="float">
</return>
<description>
Converts a string containing a decimal number into a [code]float[/code].
</description>
</method>
- <method name="to_int">
+ <method name="to_int" qualifiers="const">
<return type="int">
</return>
<description>
Converts a string containing an integer number into an [code]int[/code].
</description>
</method>
- <method name="to_lower">
+ <method name="to_lower" qualifiers="const">
<return type="String">
</return>
<description>
Returns the string converted to lowercase.
</description>
</method>
- <method name="to_upper">
+ <method name="to_upper" qualifiers="const">
<return type="String">
</return>
<description>
Returns the string converted to uppercase.
</description>
</method>
- <method name="to_utf16_buffer">
+ <method name="to_utf16_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-16 encoded [PackedByteArray] (which is an array of bytes).
</description>
</method>
- <method name="to_utf32_buffer">
+ <method name="to_utf32_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-32 encoded [PackedByteArray] (which is an array of bytes).
</description>
</method>
- <method name="to_utf8_buffer">
+ <method name="to_utf8_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-8 encode [PackedByteArray] (which is an array of bytes). The conversion is a bit slower than [method to_ascii_buffer], but supports all UTF-8 characters. Therefore, you should prefer this function over [method to_ascii_buffer].
</description>
</method>
- <method name="trim_prefix">
+ <method name="trim_prefix" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="prefix" type="String">
@@ -861,7 +895,7 @@
Removes a given string from the start if it starts with it or leaves the string unchanged.
</description>
</method>
- <method name="trim_suffix">
+ <method name="trim_suffix" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="suffix" type="String">
@@ -870,7 +904,7 @@
Removes a given string from the end if it ends with it or leaves the string unchanged.
</description>
</method>
- <method name="unicode_at">
+ <method name="unicode_at" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="at" type="int">
@@ -879,7 +913,7 @@
Returns the character code at position [code]at[/code].
</description>
</method>
- <method name="uri_decode">
+ <method name="uri_decode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -894,7 +928,7 @@
[/codeblocks]
</description>
</method>
- <method name="uri_encode">
+ <method name="uri_encode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -909,14 +943,14 @@
[/codeblocks]
</description>
</method>
- <method name="validate_node_name">
+ <method name="validate_node_name" qualifiers="const">
<return type="String">
</return>
<description>
Removes any characters from the string that are prohibited in [Node] names ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code]).
</description>
</method>
- <method name="xml_escape">
+ <method name="xml_escape" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="escape_quotes" type="bool" default="false">
@@ -925,7 +959,7 @@
Returns a copy of the string with special characters escaped using the XML standard. If [code]escape_quotes[/code] is [code]true[/code], the single quote ([code]'[/code]) and double quote ([code]"[/code]) characters are also escaped.
</description>
</method>
- <method name="xml_unescape">
+ <method name="xml_unescape" qualifiers="const">
<return type="String">
</return>
<description>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index af0074f080..be32f6a234 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -4,7 +4,7 @@
An optimized string type for unique names.
</brief_description>
<description>
- [StringName]s are immutable strings designed for general-purpose represention of unique names. [StringName] ensures that only one instance of a given name exists (so two [StringName]s with the same value are the same object). Comparing them is much faster than with regular [String]s, because only the pointers are compared, not the whole strings.
+ [StringName]s are immutable strings designed for general-purpose representation of unique names. [StringName] ensures that only one instance of a given name exists (so two [StringName]s with the same value are the same object). Comparing them is much faster than with regular [String]s, because only the pointers are compared, not the whole strings.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index df9680bf28..24c114c18b 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -261,7 +261,7 @@
If [code]true[/code], tabs can be rearranged with mouse drag.
</member>
<member name="scrolling_enabled" type="bool" setter="set_scrolling_enabled" getter="get_scrolling_enabled" default="true">
- if [code]true[/code], the mouse's scroll wheel cab be used to navigate the scroll view.
+ if [code]true[/code], the mouse's scroll wheel can be used to navigate the scroll view.
</member>
<member name="tab_align" type="int" setter="set_tab_align" getter="get_tab_align" enum="Tabs.TabAlign" default="1">
The alignment of all tabs. See [enum TabAlign] for details.
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 99eb8b81d4..69bf823ccd 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -145,7 +145,7 @@
<argument index="4" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
- Draw outilines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw outlines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="get_dropcap_lines" qualifiers="const">
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 5635ec2be0..4a41b68fee 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -359,7 +359,7 @@
<argument index="0" name="font" type="RID">
</argument>
<description>
- Returns extra spacing for each glyphs in pixels.
+ Returns extra spacing for each glyph in pixels.
</description>
</method>
<method name="font_get_spacing_space" qualifiers="const">
@@ -368,7 +368,7 @@
<argument index="0" name="font" type="RID">
</argument>
<description>
- Sets extra spacing for each glyphs in pixels.
+ Sets extra spacing for each glyph in pixels.
</description>
</method>
<method name="font_get_supported_chars" qualifiers="const">
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index 5265e75429..807d8033c1 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Counts down a specified interval and emits a signal on reaching 0. Can be set to repeat or "one-shot" mode.
- [b]Note:[/b] To create an one-shot timer without instantiating a node, use [method SceneTree.create_timer].
+ [b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml
index d75b81eece..9d8721e2de 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform.xml
@@ -58,14 +58,14 @@
Constructs a Transform from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
</description>
</method>
- <method name="affine_inverse">
+ <method name="affine_inverse" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description>
</method>
- <method name="interpolate_with">
+ <method name="interpolate_with" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="xform" type="Transform">
@@ -76,14 +76,14 @@
Interpolates the transform to other Transform by weight amount (on the range of 0.0 to 1.0).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="xform" type="Transform">
@@ -92,7 +92,7 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
- <method name="looking_at">
+ <method name="looking_at" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="target" type="Vector3">
@@ -153,14 +153,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -171,7 +171,7 @@
Rotates the transform around the given axis by the given angle (in radians), using matrix multiplication. The axis must be a normalized vector.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -180,7 +180,7 @@
Scales basis and origin of the transform by the given scale factor, using matrix multiplication.
</description>
</method>
- <method name="translated">
+ <method name="translated" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="offset" type="Vector3">
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 406774cbfe..6ae7fbcf79 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -54,14 +54,14 @@
Constructs the transform from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three column vectors).
</description>
</method>
- <method name="affine_inverse">
+ <method name="affine_inverse" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description>
</method>
- <method name="basis_xform">
+ <method name="basis_xform" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="v" type="Vector2">
@@ -71,7 +71,7 @@
This method does not account for translation (the origin vector).
</description>
</method>
- <method name="basis_xform_inv">
+ <method name="basis_xform_inv" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="v" type="Vector2">
@@ -81,28 +81,28 @@
This method does not account for translation (the origin vector).
</description>
</method>
- <method name="get_origin">
+ <method name="get_origin" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the transform's origin (translation).
</description>
</method>
- <method name="get_rotation">
+ <method name="get_rotation" qualifiers="const">
<return type="float">
</return>
<description>
Returns the transform's rotation (in radians).
</description>
</method>
- <method name="get_scale">
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the scale.
</description>
</method>
- <method name="interpolate_with">
+ <method name="interpolate_with" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="xform" type="Transform2D">
@@ -113,14 +113,14 @@
Returns a transform interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use [method affine_inverse] for transforms with scaling).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="xform" type="Transform2D">
@@ -185,14 +185,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors (scale of 1 or -1).
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="phi" type="float">
@@ -201,7 +201,7 @@
Rotates the transform by the given angle (in radians), using matrix multiplication.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="scale" type="Vector2">
@@ -210,7 +210,7 @@
Scales the transform by the given scale factor, using matrix multiplication.
</description>
</method>
- <method name="translated">
+ <method name="translated" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="offset" type="Vector2">
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index b32bb1e2d9..00cca40093 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -23,7 +23,7 @@
tween.Start();
[/csharp]
[/codeblocks]
- Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component.
+ Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (e.g. [code]position:x[/code]), where it would only apply to that particular component.
Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url]
</description>
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index a0330de4fa..aba6183124 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -186,7 +186,7 @@
<return type="int">
</return>
<description>
- Return how many element are in the history.
+ Return how many elements are in the history.
</description>
</method>
<method name="get_version" qualifiers="const">
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 4159a38d96..b979425b85 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -53,14 +53,14 @@
Constructs a new [Vector2] from the given [code]x[/code] and [code]y[/code].
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="angle">
+ <method name="angle" qualifiers="const">
<return type="float">
</return>
<description>
@@ -69,7 +69,7 @@
Equivalent to the result of [method @GlobalScope.atan2] when called with the vector's [member y] and [member x] as parameters: [code]atan2(y, x)[/code].
</description>
</method>
- <method name="angle_to">
+ <method name="angle_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -78,7 +78,7 @@
Returns the angle to the given vector, in radians.
</description>
</method>
- <method name="angle_to_point">
+ <method name="angle_to_point" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -87,14 +87,14 @@
Returns the angle between the line connecting the two points and the X axis, in radians.
</description>
</method>
- <method name="aspect">
+ <method name="aspect" qualifiers="const">
<return type="float">
</return>
<description>
Returns the aspect ratio of this vector, the ratio of [member x] to [member y].
</description>
</method>
- <method name="bounce">
+ <method name="bounce" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -103,14 +103,14 @@
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
</method>
- <method name="ceil">
+ <method name="ceil" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded up (towards positive infinity).
</description>
</method>
- <method name="clamped">
+ <method name="clamped" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="length" type="float">
@@ -119,7 +119,7 @@
Returns the vector with a maximum length by limiting its length to [code]length[/code].
</description>
</method>
- <method name="cross">
+ <method name="cross" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector2">
@@ -128,7 +128,7 @@
Returns the cross product of this vector and [code]with[/code].
</description>
</method>
- <method name="cubic_interpolate">
+ <method name="cubic_interpolate" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -143,7 +143,7 @@
Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="direction_to">
+ <method name="direction_to" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -152,7 +152,7 @@
Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
- <method name="distance_squared_to">
+ <method name="distance_squared_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -162,7 +162,7 @@
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -171,7 +171,7 @@
Returns the distance between this vector and [code]to[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector2">
@@ -183,14 +183,14 @@
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description>
</method>
- <method name="floor">
+ <method name="floor" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded down (towards negative infinity).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Vector2">
@@ -199,21 +199,21 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length (magnitude) of this vector.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
@@ -221,7 +221,7 @@
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -232,7 +232,7 @@
Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="move_toward">
+ <method name="move_toward" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -243,7 +243,7 @@
Moves the vector toward [code]to[/code] by the fixed [code]delta[/code] amount.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -390,14 +390,14 @@
<description>
</description>
</method>
- <method name="orthogonal">
+ <method name="orthogonal" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns a perpendicular vector rotated 90 degrees counter-clockwise compared to the original, with the same length.
</description>
</method>
- <method name="posmod">
+ <method name="posmod" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="mod" type="float">
@@ -406,7 +406,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
</description>
</method>
- <method name="posmodv">
+ <method name="posmodv" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="modv" type="Vector2">
@@ -415,7 +415,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -424,7 +424,7 @@
Returns the vector projected onto the vector [code]b[/code].
</description>
</method>
- <method name="reflect">
+ <method name="reflect" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -433,7 +433,7 @@
Returns the vector reflected from a plane defined by the given normal.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="phi" type="float">
@@ -442,21 +442,21 @@
Returns the vector rotated by [code]phi[/code] radians. See also [method @GlobalScope.deg2rad].
</description>
</method>
- <method name="round">
+ <method name="round" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero.
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -468,7 +468,7 @@
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
- <method name="slide">
+ <method name="slide" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -477,7 +477,7 @@
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
- <method name="snapped">
+ <method name="snapped" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="step" type="Vector2">
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index a4ea5c2742..b38b968ba3 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -50,14 +50,14 @@
Constructs a new [Vector2i] from the given [code]x[/code] and [code]y[/code].
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector2i">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="aspect">
+ <method name="aspect" qualifiers="const">
<return type="float">
</return>
<description>
@@ -212,7 +212,7 @@
<description>
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector2i">
</return>
<description>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index ea80b7c248..bd568e01ec 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -55,14 +55,14 @@
Returns a [Vector3] with the given components.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="angle_to">
+ <method name="angle_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector3">
@@ -71,7 +71,7 @@
Returns the unsigned minimum angle to the given vector, in radians.
</description>
</method>
- <method name="bounce">
+ <method name="bounce" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -80,14 +80,14 @@
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
</method>
- <method name="ceil">
+ <method name="ceil" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components rounded up (towards positive infinity).
</description>
</method>
- <method name="cross">
+ <method name="cross" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="with" type="Vector3">
@@ -96,7 +96,7 @@
Returns the cross product of this vector and [code]b[/code].
</description>
</method>
- <method name="cubic_interpolate">
+ <method name="cubic_interpolate" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -111,7 +111,7 @@
Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="direction_to">
+ <method name="direction_to" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -120,7 +120,7 @@
Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
- <method name="distance_squared_to">
+ <method name="distance_squared_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -130,7 +130,7 @@
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -139,7 +139,7 @@
Returns the distance between this vector and [code]b[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -151,21 +151,21 @@
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description>
</method>
- <method name="floor">
+ <method name="floor" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components rounded down (towards negative infinity).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the inverse of the vector. This is the same as [code]Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )[/code].
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Vector3">
@@ -174,21 +174,21 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length (magnitude) of this vector.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
@@ -196,7 +196,7 @@
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -207,21 +207,21 @@
Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="max_axis">
+ <method name="max_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
- <method name="min_axis">
+ <method name="min_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_Z].
</description>
</method>
- <method name="move_toward">
+ <method name="move_toward" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -232,7 +232,7 @@
Moves this vector toward [code]to[/code] by the fixed [code]delta[/code] amount.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -395,7 +395,7 @@
<description>
</description>
</method>
- <method name="outer">
+ <method name="outer" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="with" type="Vector3">
@@ -404,7 +404,7 @@
Returns the outer product with [code]b[/code].
</description>
</method>
- <method name="posmod">
+ <method name="posmod" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="mod" type="float">
@@ -413,7 +413,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
</description>
</method>
- <method name="posmodv">
+ <method name="posmodv" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="modv" type="Vector3">
@@ -422,7 +422,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -431,7 +431,7 @@
Returns this vector projected onto another vector [code]b[/code].
</description>
</method>
- <method name="reflect">
+ <method name="reflect" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -440,7 +440,7 @@
Returns this vector reflected from a plane defined by the given normal.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="by_axis" type="Vector3">
@@ -451,21 +451,21 @@
Rotates this vector around a given axis by [code]phi[/code] radians. The axis must be a normalized vector.
</description>
</method>
- <method name="round">
+ <method name="round" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns this vector with all components rounded to the nearest integer, with halfway cases rounded away from zero.
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a vector with each component set to one or negative one, depending on the signs of this vector's components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
- <method name="signed_angle_to">
+ <method name="signed_angle_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector3">
@@ -476,7 +476,7 @@
Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and negative in a clockwise direction when viewed from the side specified by the [code]axis[/code].
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -488,7 +488,7 @@
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
- <method name="slide">
+ <method name="slide" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -497,7 +497,7 @@
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
- <method name="snapped">
+ <method name="snapped" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="step" type="Vector3">
@@ -506,7 +506,7 @@
Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
</description>
</method>
- <method name="to_diagonal_matrix">
+ <method name="to_diagonal_matrix" qualifiers="const">
<return type="Basis">
</return>
<description>
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index a1ae2aceab..ea5945f5b7 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -52,20 +52,20 @@
Returns a [Vector3i] with the given components.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector3i">
</return>
<description>
</description>
</method>
- <method name="max_axis">
+ <method name="max_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
- <method name="min_axis">
+ <method name="min_axis" qualifiers="const">
<return type="int">
</return>
<description>
@@ -220,7 +220,7 @@
<description>
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector3i">
</return>
<description>
diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml
index 59b501660a..17fc2f8c4d 100644
--- a/doc/classes/VisualShaderNodeCustom.xml
+++ b/doc/classes/VisualShaderNodeCustom.xml
@@ -20,7 +20,7 @@
<return type="String">
</return>
<description>
- Override this method to define the path to the associated custom node in the Visual Shader Editor's members dialog. The path may looks like [code]"MyGame/MyFunctions/Noise"[/code].
+ Override this method to define the path to the associated custom node in the Visual Shader Editor's members dialog. The path may look like [code]"MyGame/MyFunctions/Noise"[/code].
Defining this method is [b]optional[/b]. If not overridden, the node will be filed under the "Addons" category.
</description>
</method>
diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml
index 72be31872d..6b042f6172 100644
--- a/doc/classes/VisualShaderNodeDeterminant.xml
+++ b/doc/classes/VisualShaderNodeDeterminant.xml
@@ -4,7 +4,7 @@
Calculates the determinant of a [Transform] within the visual shader graph.
</brief_description>
<description>
- Translates to [code]deteminant(x)[/code] in the shader language.
+ Translates to [code]determinant(x)[/code] in the shader language.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml
index f571edaab3..c2cbf41f45 100644
--- a/doc/classes/VisualShaderNodeExpression.xml
+++ b/doc/classes/VisualShaderNodeExpression.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Custom Godot Shading Language expression, with a custom amount of input and output ports.
- The provided code is directly injected into the graph's matching shader function ([code]vertex[/code], [code]fragment[/code], or [code]light[/code]), so it cannot be used to to declare functions, varyings, uniforms, or global constants. See [VisualShaderNodeGlobalExpression] for such global definitions.
+ The provided code is directly injected into the graph's matching shader function ([code]vertex[/code], [code]fragment[/code], or [code]light[/code]), so it cannot be used to declare functions, varyings, uniforms, or global constants. See [VisualShaderNodeGlobalExpression] for such global definitions.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeFaceForward.xml b/doc/classes/VisualShaderNodeFaceForward.xml
index 5ef08ea8c2..48f84e5495 100644
--- a/doc/classes/VisualShaderNodeFaceForward.xml
+++ b/doc/classes/VisualShaderNodeFaceForward.xml
@@ -4,7 +4,7 @@
Returns the vector that points in the same direction as a reference vector within the visual shader graph.
</brief_description>
<description>
- Translates to [code]faceforward(N, I, Nref)[/code] in the shader language. The function has three vector parameters: [code]N[/code], the vector to orient, [code]I[/code], the incident vector, and [code]Nref[/code], the reference vector. If the dot product of [code]I[/code] and [code]Nref[/code] is smaller than zero the return value is [code]N[/code]. Otherwise [code]-N[/code] is returned.
+ Translates to [code]faceforward(N, I, Nref)[/code] in the shader language. The function has three vector parameters: [code]N[/code], the vector to orient, [code]I[/code], the incident vector, and [code]Nref[/code], the reference vector. If the dot product of [code]I[/code] and [code]Nref[/code] is smaller than zero the return value is [code]N[/code]. Otherwise, [code]-N[/code] is returned.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml
index afa14c776e..be3f7f173d 100644
--- a/doc/classes/VisualShaderNodeGroupBase.xml
+++ b/doc/classes/VisualShaderNodeGroupBase.xml
@@ -74,7 +74,7 @@
<return type="String">
</return>
<description>
- Returns a [String] description of the input ports as as colon-separated list using the format [code]id,type,name;[/code] (see [method add_input_port]).
+ Returns a [String] description of the input ports as a colon-separated list using the format [code]id,type,name;[/code] (see [method add_input_port]).
</description>
</method>
<method name="get_output_port_count" qualifiers="const">
@@ -88,7 +88,7 @@
<return type="String">
</return>
<description>
- Returns a [String] description of the output ports as as colon-separated list using the format [code]id,type,name;[/code] (see [method add_output_port]).
+ Returns a [String] description of the output ports as a colon-separated list using the format [code]id,type,name;[/code] (see [method add_output_port]).
</description>
</method>
<method name="has_input_port" qualifiers="const">
diff --git a/doc/classes/VisualShaderNodeIf.xml b/doc/classes/VisualShaderNodeIf.xml
index ad0b21a370..418999863b 100644
--- a/doc/classes/VisualShaderNodeIf.xml
+++ b/doc/classes/VisualShaderNodeIf.xml
@@ -4,7 +4,7 @@
Compares two floating-point numbers in order to return a required vector within the visual shader graph.
</brief_description>
<description>
- First two ports are scalar floatin-point numbers to compare, third is tolerance comparison amount and last three ports represents a vectors returned if [code]a == b[/code], [code]a &gt; b[/code] and [code]a &lt; b[/code] respectively.
+ First two ports are scalar floating-point numbers to compare, third is tolerance comparison amount and last three ports represents a vectors returned if [code]a == b[/code], [code]a &gt; b[/code] and [code]a &lt; b[/code] respectively.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml
index 8e819b011c..067f78dffe 100644
--- a/doc/classes/VisualShaderNodeInput.xml
+++ b/doc/classes/VisualShaderNodeInput.xml
@@ -14,7 +14,7 @@
<return type="String">
</return>
<description>
- Returns a translated name of the current constant in the Godot Shader Language. eg. [code]"ALBEDO"[/code] if the [member input_name] equal to [code]"albedo"[/code].
+ Returns a translated name of the current constant in the Godot Shader Language. E.g. [code]"ALBEDO"[/code] if the [member input_name] equal to [code]"albedo"[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/VisualShaderNodeSDFToScreenUV.xml b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
index ea04180095..40fb66e364 100644
--- a/doc/classes/VisualShaderNodeSDFToScreenUV.xml
+++ b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeSDFToScreenUV" inherits="VisualShaderNode" version="4.0">
<brief_description>
- A function to convert a SDF (signed-distance field) to screen UV, to be used within the visual shader graph.
+ A function to convert an SDF (signed-distance field) to screen UV, to be used within the visual shader graph.
</brief_description>
<description>
Translates to [code]sdf_to_screen_uv(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeScreenUVToSDF.xml b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
index 438c8dc67b..2e121ffc54 100644
--- a/doc/classes/VisualShaderNodeScreenUVToSDF.xml
+++ b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeScreenUVToSDF" inherits="VisualShaderNode" version="4.0">
<brief_description>
- A function to convert screen UV to a SDF (signed-distance field), to be used within the visual shader graph.
+ A function to convert screen UV to an SDF (signed-distance field), to be used within the visual shader graph.
</brief_description>
<description>
Translates to [code]screen_uv_to_sdf(uv)[/code] in the shader language. If the UV port isn't connected, [code]SCREEN_UV[/code] is used instead.
diff --git a/doc/classes/VisualShaderNodeSmoothStep.xml b/doc/classes/VisualShaderNodeSmoothStep.xml
index fa22d16da8..0ed53a8c26 100644
--- a/doc/classes/VisualShaderNodeSmoothStep.xml
+++ b/doc/classes/VisualShaderNodeSmoothStep.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language.
- Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials.
+ Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise, the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeTextureSDF.xml b/doc/classes/VisualShaderNodeTextureSDF.xml
index 7d3d654bd0..b5c89c2c31 100644
--- a/doc/classes/VisualShaderNodeTextureSDF.xml
+++ b/doc/classes/VisualShaderNodeTextureSDF.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTextureSDF" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Performs a SDF (signed-distance field) texture lookup within the visual shader graph.
+ Performs an SDF (signed-distance field) texture lookup within the visual shader graph.
</brief_description>
<description>
Translates to [code]texture_sdf(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeTextureSDFNormal.xml b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
index 5dbf3e545a..25fe1c4b28 100644
--- a/doc/classes/VisualShaderNodeTextureSDFNormal.xml
+++ b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTextureSDFNormal" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Performs a SDF (signed-distance field) normal texture lookup within the visual shader graph.
+ Performs an SDF (signed-distance field) normal texture lookup within the visual shader graph.
</brief_description>
<description>
Translates to [code]texture_sdf_normal(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index 03e8bee7d5..8da1eb3c88 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -4,7 +4,7 @@
Boolean built-in type.
</brief_description>
<description>
- Boolean is a built-in type. There are two boolean values: [code]true[/code] and [code]false[/code]. You can think of it as an switch with on or off (1 or 0) setting. Booleans are used in programming for logic in condition statements, like [code]if[/code] statements.
+ Boolean is a built-in type. There are two boolean values: [code]true[/code] and [code]false[/code]. You can think of it as a switch with on or off (1 or 0) setting. Booleans are used in programming for logic in condition statements, like [code]if[/code] statements.
Booleans can be directly used in [code]if[/code] statements. The code below demonstrates this on the [code]if can_shoot:[/code] line. You don't need to use [code]== true[/code], you only need [code]if can_shoot:[/code]. Similarly, use [code]if not can_shoot:[/code] rather than [code]== false[/code].
[codeblocks]
[gdscript]
@@ -49,6 +49,7 @@
[/csharp]
[/codeblocks]
The following code will set [code]can_shoot[/code] to [code]false[/code] and start a timer. This will prevent player from shooting until the timer runs out. Next [code]can_shoot[/code] will be set to [code]true[/code] again allowing player to shoot once again.
+ [codeblocks]
[gdscript]
var _can_shoot = true
onready var _cool_down = $CoolDownTimer
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index baa60f5526..f40036d628 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -506,7 +506,8 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
UInt32 size = 0;
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
- AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
+ AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
+ ERR_FAIL_NULL_V_MSG(audioDevices, list, "Out of memory.");
AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
@@ -515,14 +516,15 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
- AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
+ AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
+ ERR_FAIL_NULL_V_MSG(bufferList, list, "Out of memory.");
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
channelCount += bufferList->mBuffers[j].mNumberChannels;
- free(bufferList);
+ memfree(bufferList);
if (channelCount >= 1) {
CFStringRef cfname;
@@ -534,17 +536,18 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
- char *buffer = (char *)malloc(maxSize);
+ char *buffer = (char *)memalloc(maxSize);
+ ERR_FAIL_NULL_V_MSG(buffer, list, "Out of memory.");
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
// Append the ID to the name in case we have devices with duplicate name
list.push_back(String(buffer) + " (" + itos(audioDevices[i]) + ")");
}
- free(buffer);
+ memfree(buffer);
}
}
- free(audioDevices);
+ memfree(audioDevices);
return list;
}
@@ -561,7 +564,8 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
UInt32 size = 0;
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
- AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
+ AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
+ ERR_FAIL_NULL_MSG(audioDevices, "Out of memory.");
AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
@@ -570,14 +574,15 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
- AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
+ AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
+ ERR_FAIL_NULL_MSG(bufferList, "Out of memory.");
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
channelCount += bufferList->mBuffers[j].mNumberChannels;
- free(bufferList);
+ memfree(bufferList);
if (channelCount >= 1) {
CFStringRef cfname;
@@ -589,7 +594,8 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
- char *buffer = (char *)malloc(maxSize);
+ char *buffer = (char *)memalloc(maxSize);
+ ERR_FAIL_NULL_MSG(buffer, "Out of memory.");
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
String name = String(buffer) + " (" + itos(audioDevices[i]) + ")";
if (name == device) {
@@ -598,11 +604,11 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
}
}
- free(buffer);
+ memfree(buffer);
}
}
- free(audioDevices);
+ memfree(audioDevices);
}
if (!found) {
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 6b24a85ff6..4c08380dd0 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -240,6 +240,8 @@ uint8_t FileAccessUnix::get_8() const {
}
int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
int read = fread(p_dst, 1, p_length, f);
check_errors();
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index 19fab1d475..e47046e3ae 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -35,6 +35,10 @@
#include "core/os/thread.h"
#include "core/string/ustring.h"
+#ifdef PTHREAD_BSD_SET_NAME
+#include <pthread_np.h>
+#endif
+
static Error set_name(const String &p_name) {
#ifdef PTHREAD_NO_RENAME
return ERR_UNAVAILABLE;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 9584dd3f67..469d80368d 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -119,7 +119,7 @@ static void update_external_dependency_for_store(VkSubpassDependency &dependency
}
if (is_depth) {
- // Depth resources have addtional stages that may be interested in them
+ // Depth resources have additional stages that may be interested in them
dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
@@ -3108,7 +3108,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- // NOTE: Perhaps the valid stages/accesses for a given onwner should be a property of the owner. (Here and places like _get_buffer_from_owner)
+ // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner)
const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT;
constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
@@ -3250,7 +3250,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
Vector<VkAttachmentReference> depth_stencil_references;
Vector<VkAttachmentReference> resolve_references;
- // Set up a dependencies from/to external equivalent to the default (implicit) one, and then amend them
+ // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them
const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
@@ -3279,7 +3279,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
// For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write
- // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution syncronization vs.
+ // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs.
// the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
// stage
switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) {
@@ -3424,12 +3424,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// NOTE: Big Mallet Approach -- any layout transition causes a full barrier
if (reference.layout != description.initialLayout) {
- // NOTE: this should be smarter based on the textures knowledge of it's previous role
+ // NOTE: this should be smarter based on the texture's knowledge of its previous role
dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
if (reference.layout != description.finalLayout) {
- // NOTE: this should be smarter based on the textures knowledge of it's subsequent role
+ // NOTE: this should be smarter based on the texture's knowledge of its subsequent role
dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
@@ -5151,7 +5151,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
- //if 0, then its sized on link time
+ //if 0, then it's sized on link time
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
@@ -5336,7 +5336,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
}
- // Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below.
+ // Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below.
_buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, src_access_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, false);
VkCommandBuffer command_buffer = frames[frame].setup_command_buffer;
@@ -5729,7 +5729,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
#endif
//create ID to associate with this pipeline
RID id = render_pipeline_owner.make_rid(pipeline);
- //now add aall the dependencies
+ //now add all the dependencies
_add_dependency(id, p_shader);
return id;
}
@@ -5780,7 +5780,7 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) {
//create ID to associate with this pipeline
RID id = compute_pipeline_owner.make_rid(pipeline);
- //now add aall the dependencies
+ //now add all the dependencies
_add_dependency(id, p_shader);
return id;
}
@@ -6817,7 +6817,7 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
// To ensure proper synchronization, we must make sure rendering is done before:
// * Some buffer is copied
- // * Another render pass happens (since we may be done
+ // * Another render pass happens (since we may be done)
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
@@ -7780,7 +7780,7 @@ uint64_t RenderingDeviceVulkan::get_memory_usage() const {
void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (local_device.is_valid() && !p_current_frame) {
- return; //flushign previous frames has no effect with local device
+ return; //flushing previous frames has no effect with local device
}
//not doing this crashes RADV (undefined behavior)
if (p_current_frame) {
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index ad740efec4..69517b17ba 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -1313,13 +1313,13 @@ Error VulkanContext::swap_buffers() {
DemoUpdateTargetIPD(demo);
// Note: a real application would position its geometry to that it's in
- // the correct locatoin for when the next image is presented. It might
+ // the correct location for when the next image is presented. It might
// also wait, so that there's less latency between any input and when
// the next image is rendered/presented. This demo program is so
// simple that it doesn't do either of those.
}
#endif
- // Wait for the image acquired semaphore to be signaled to ensure
+ // Wait for the image acquired semaphore to be signalled to ensure
// that the image won't be rendered to until the presentation
// engine has fully released ownership to the application, and it is
// okay to render to the image.
@@ -1385,7 +1385,7 @@ Error VulkanContext::swap_buffers() {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
- // If we are using separate queues we have to wait for image ownership,
+ // If we are using separate queues, we have to wait for image ownership,
// otherwise wait for draw complete
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 35f61c0623..b1b3fc9092 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -253,6 +253,8 @@ uint8_t FileAccessWindows::get_8() const {
}
int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!f, -1);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == WRITE) {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 804f02765c..de8f8b1d3b 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -4439,6 +4439,8 @@ void AnimationTrackEditor::_add_track(int p_type) {
}
adding_track_type = p_type;
pick_track->popup_scenetree_dialog();
+ pick_track->get_filter_line_edit()->clear();
+ pick_track->get_filter_line_edit()->grab_focus();
}
void AnimationTrackEditor::_new_track_property_selected(String p_name) {
@@ -5635,6 +5637,70 @@ void AnimationTrackEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_step_changed", PropertyInfo(Variant::FLOAT, "step")));
}
+void AnimationTrackEditor::_pick_track_filter_text_changed(const String &p_newtext) {
+ TreeItem *root_item = pick_track->get_scene_tree()->get_scene_tree()->get_root();
+
+ Vector<Node *> select_candidates;
+ Node *to_select = nullptr;
+
+ String filter = pick_track->get_filter_line_edit()->get_text();
+
+ _pick_track_select_recursive(root_item, filter, select_candidates);
+
+ if (!select_candidates.is_empty()) {
+ for (int i = 0; i < select_candidates.size(); ++i) {
+ Node *candidate = select_candidates[i];
+
+ if (((String)candidate->get_name()).to_lower().begins_with(filter.to_lower())) {
+ to_select = candidate;
+ break;
+ }
+ }
+
+ if (!to_select) {
+ to_select = select_candidates[0];
+ }
+ }
+
+ pick_track->get_scene_tree()->set_selected(to_select);
+}
+
+void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates) {
+ if (!p_item) {
+ return;
+ }
+
+ NodePath np = p_item->get_metadata(0);
+ Node *node = get_node(np);
+
+ if (p_filter != String() && ((String)node->get_name()).findn(p_filter) != -1) {
+ p_select_candidates.push_back(node);
+ }
+
+ TreeItem *c = p_item->get_children();
+
+ while (c) {
+ _pick_track_select_recursive(c, p_filter, p_select_candidates);
+ c = c->get_next();
+ }
+}
+
+void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> k = p_ie;
+
+ if (k.is_valid()) {
+ switch (k->get_keycode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+ pick_track->get_scene_tree()->get_scene_tree()->call("_gui_input", k);
+ pick_track->get_filter_line_edit()->accept_event();
+ } break;
+ }
+ }
+}
+
AnimationTrackEditor::AnimationTrackEditor() {
root = nullptr;
@@ -5805,8 +5871,12 @@ AnimationTrackEditor::AnimationTrackEditor() {
pick_track = memnew(SceneTreeDialog);
add_child(pick_track);
+ pick_track->register_text_enter(pick_track->get_filter_line_edit());
pick_track->set_title(TTR("Pick a node to animate:"));
pick_track->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_node_selected));
+ pick_track->get_filter_line_edit()->connect("text_changed", callable_mp(this, &AnimationTrackEditor::_pick_track_filter_text_changed));
+ pick_track->get_filter_line_edit()->connect("gui_input", callable_mp(this, &AnimationTrackEditor::_pick_track_filter_input));
+
prop_selector = memnew(PropertySelector);
add_child(prop_selector);
prop_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_property_selected));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index e8e4f915fa..c25865effb 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -499,6 +499,10 @@ class AnimationTrackEditor : public VBoxContainer {
void _insert_animation_key(NodePath p_path, const Variant &p_value);
+ void _pick_track_filter_text_changed(const String &p_newtext);
+ void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
+ void _pick_track_filter_input(const Ref<InputEvent> &p_ie);
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 47ea8cbe2a..e29c9593c3 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -394,13 +394,22 @@ void DocTools::generate(bool p_basic_types) {
method.qualifiers += " ";
}
method.qualifiers += "const";
- } else if (E->get().flags & METHOD_FLAG_VARARG) {
+ }
+
+ if (E->get().flags & METHOD_FLAG_VARARG) {
if (method.qualifiers != "") {
method.qualifiers += " ";
}
method.qualifiers += "vararg";
}
+ if (E->get().flags & METHOD_FLAG_STATIC) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "static";
+ }
+
for (int i = -1; i < E->get().arguments.size(); i++) {
if (i == -1) {
#ifdef DEBUG_METHODS_ENABLED
@@ -647,6 +656,20 @@ void DocTools::generate(bool p_basic_types) {
method.qualifiers += "vararg";
}
+ if (mi.flags & METHOD_FLAG_CONST) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "const";
+ }
+
+ if (mi.flags & METHOD_FLAG_STATIC) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "static";
+ }
+
c.methods.push_back(method);
}
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 7f5f51cf70..3c0fe1571c 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -874,6 +874,20 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
continue;
}
+ String importer_type = config->get_value("remap", "importer");
+
+ if (importer_type == "keep") {
+ //just keep file as-is
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path);
+ err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+
+ if (err != OK) {
+ return err;
+ }
+
+ continue;
+ }
+
List<String> remaps;
config->get_section_keys("remap", &remaps);
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 6d694358bf..f78da9569f 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1076,9 +1076,9 @@ EditorFileDialog::Access EditorFileDialog::get_access() const {
}
void EditorFileDialog::_make_dir_confirm() {
- Error err = dir_access->make_dir(makedirname->get_text());
+ Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
if (err == OK) {
- dir_access->change_dir(makedirname->get_text());
+ dir_access->change_dir(makedirname->get_text().strip_edges());
invalidate();
update_filters();
update_dir();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index dce022e86e..fb0dc57501 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -405,6 +405,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
memdelete(f);
+ if (importer_name == "keep") {
+ return false; //keep mode, do not reimport
+ }
+
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
if (importer->get_format_version() > version) {
@@ -1532,6 +1536,10 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
source_file_options[p_files[i]] = Map<StringName, Variant>();
importer_name = file_importer_name;
+ if (importer_name == "keep") {
+ continue; //do nothing
+ }
+
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT);
List<ResourceImporter::ImportOption> options;
@@ -1555,6 +1563,10 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
base_paths[p_files[i]] = ResourceFormatImporter::get_singleton()->get_import_base_path(p_files[i]);
}
+ if (importer_name == "keep") {
+ return OK; // (do nothing)
+ }
+
ERR_FAIL_COND_V(importer_name == String(), ERR_UNCONFIGURED);
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
@@ -1668,7 +1680,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
return err;
}
-void EditorFileSystem::_reimport_file(const String &p_file) {
+void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options, const String &p_custom_importer) {
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(p_file, &fs, cpos);
@@ -1677,23 +1689,32 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
//try to obtain existing params
Map<StringName, Variant> params;
- String importer_name;
+ String importer_name; //empty by default though
+
+ if (p_custom_importer != String()) {
+ importer_name = p_custom_importer;
+ }
+ if (p_custom_options != nullptr) {
+ params = *p_custom_options;
+ }
if (FileAccess::exists(p_file + ".import")) {
//use existing
- Ref<ConfigFile> cf;
- cf.instance();
- Error err = cf->load(p_file + ".import");
- if (err == OK) {
- if (cf->has_section("params")) {
- List<String> sk;
- cf->get_section_keys("params", &sk);
- for (List<String>::Element *E = sk.front(); E; E = E->next()) {
- params[E->get()] = cf->get_value("params", E->get());
+ if (p_custom_options == nullptr) {
+ Ref<ConfigFile> cf;
+ cf.instance();
+ Error err = cf->load(p_file + ".import");
+ if (err == OK) {
+ if (cf->has_section("params")) {
+ List<String> sk;
+ cf->get_section_keys("params", &sk);
+ for (List<String>::Element *E = sk.front(); E; E = E->next()) {
+ params[E->get()] = cf->get_value("params", E->get());
+ }
+ }
+ if (p_custom_importer == String() && cf->has_section("remap")) {
+ importer_name = cf->get_value("remap", "importer");
}
- }
- if (cf->has_section("remap")) {
- importer_name = cf->get_value("remap", "importer");
}
}
@@ -1701,6 +1722,16 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
late_added_files.insert(p_file); //imported files do not call update_file(), but just in case..
}
+ if (importer_name == "keep") {
+ //keep files, do nothing.
+ fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
+ fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import");
+ fs->files[cpos]->deps.clear();
+ fs->files[cpos]->type = "";
+ fs->files[cpos]->import_valid = false;
+ EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
+ return;
+ }
Ref<ResourceImporter> importer;
bool load_default = false;
//find the importer
@@ -1887,6 +1918,10 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<Str
}
}
+void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params) {
+ _reimport_file(p_file, &p_custom_params, p_importer);
+}
+
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
{
// Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 59bde238a8..6f4f058503 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -203,7 +203,7 @@ class EditorFileSystem : public Node {
void _update_extensions();
- void _reimport_file(const String &p_file);
+ void _reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options = nullptr, const String &p_custom_importer = String());
Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);
bool _test_for_reimport(const String &p_path, bool p_only_imported_files);
@@ -257,6 +257,8 @@ public:
void reimport_files(const Vector<String> &p_files);
+ void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params);
+
void update_script_classes();
bool is_group_file(const String &p_path) const;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 74b874b54e..9b03731fd8 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -2436,10 +2436,10 @@ void EditorInspector::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
set_process(is_visible_in_tree());
+ _update_inspector_bg();
}
if (p_what == NOTIFICATION_ENTER_TREE) {
- _update_inspector_bg();
if (!sub_inspector) {
get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f0e53e7ef5..2e402d013b 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -102,6 +102,7 @@
#include "editor/import/resource_importer_texture.h"
#include "editor/import/resource_importer_texture_atlas.h"
#include "editor/import/resource_importer_wav.h"
+#include "editor/import/scene_import_settings.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "editor/import_dock.h"
#include "editor/multi_node_edit.h"
@@ -1089,13 +1090,23 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->clear_filters();
List<String> preferred;
- for (int i = 0; i < extensions.size(); i++) {
- if (p_resource->is_class("Script") && (extensions[i] == "tres" || extensions[i] == "res" || extensions[i] == "xml")) {
+ for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
+ if (p_resource->is_class("Script") && (E->get() == "tres" || E->get() == "res")) {
//this serves no purpose and confused people
continue;
}
- file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- preferred.push_back(extensions[i]);
+ file->add_filter("*." + E->get() + " ; " + E->get().to_upper());
+ preferred.push_back(E->get());
+ }
+ // Lowest priority extension
+ List<String>::Element *res_element = preferred.find("res");
+ if (res_element) {
+ preferred.move_to_back(res_element);
+ }
+ // Highest priority extension
+ List<String>::Element *tres_element = preferred.find("tres");
+ if (tres_element) {
+ preferred.move_to_front(tres_element);
}
if (p_at_path != String()) {
@@ -2387,11 +2398,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
_scene_tab_changed(tab_closing);
if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
- String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
- save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
- save_confirmation->popup_centered();
- break;
+ Node *scene_root = editor_data.get_edited_scene_root(tab_closing);
+ if (scene_root) {
+ String scene_filename = scene_root->get_filename();
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
+ save_confirmation->popup_centered();
+ break;
+ }
}
} else if (p_option == FILE_CLOSE) {
tab_closing = editor_data.get_edited_scene();
@@ -6166,6 +6180,9 @@ EditorNode::EditorNode() {
project_settings = memnew(ProjectSettingsEditor(&editor_data));
gui_base->add_child(project_settings);
+ scene_import_settings = memnew(SceneImportSettings);
+ gui_base->add_child(scene_import_settings);
+
export_template_manager = memnew(ExportTemplateManager);
gui_base->add_child(export_template_manager);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 91d873d16f..7e16936f5d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -88,6 +88,7 @@ class Button;
class VSplitContainer;
class Window;
class SubViewport;
+class SceneImportSettings;
class EditorNode : public Node {
GDCLASS(EditorNode, Node);
@@ -410,6 +411,7 @@ private:
EditorResourcePreview *resource_preview;
EditorFolding editor_folding;
+ SceneImportSettings *scene_import_settings;
struct BottomPanelItem {
String name;
Control *control = nullptr;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index dbe4aa55fa..2d7235038a 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2915,7 +2915,7 @@ void EditorPropertyResource::update_property() {
sub_inspector->set_use_doc_hints(true);
sub_inspector->set_sub_inspector(true);
- sub_inspector->set_enable_capitalize_paths(true);
+ sub_inspector->set_enable_capitalize_paths(bool(EDITOR_GET("interface/inspector/capitalize_properties")));
sub_inspector->connect("property_keyed", callable_mp(this, &EditorPropertyResource::_sub_inspector_property_keyed));
sub_inspector->connect("resource_selected", callable_mp(this, &EditorPropertyResource::_sub_inspector_resource_selected));
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index ef1f8030fa..814925f5c6 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -620,8 +620,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// is increased significantly more than it really should need to be.
hints["editors/3d/grid_division_level_max"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_max", PROPERTY_HINT_RANGE, "-1,3,1", PROPERTY_USAGE_DEFAULT);
- // Default smallest grid size is 1cm, 10^-2.
- _initial_set("editors/3d/grid_division_level_min", -2);
+ // Default smallest grid size is 1m, 10^0.
+ _initial_set("editors/3d/grid_division_level_min", 0);
// Lower values produce graphical artifacts regardless of view clipping planes, so limit to -2 as a lower bound.
hints["editors/3d/grid_division_level_min"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_min", PROPERTY_HINT_RANGE, "-2,2,1", PROPERTY_USAGE_DEFAULT);
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 618d953c56..bbabc08ea4 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -175,7 +175,9 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range);
+ float scale_x = get_global_transform_with_canvas().get_scale().x;
+ ERR_FAIL_COND(Math::is_zero_approx(scale_x));
+ float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range) / scale_x;
set_as_ratio(grabbing_ratio + grabbing_ofs);
update();
}
@@ -300,8 +302,10 @@ void EditorSpinSlider::_notification(int p_what) {
grabber->set_texture(grabber_tex);
}
+ Vector2 scale = get_global_transform_with_canvas().get_scale();
+ grabber->set_scale(scale);
grabber->set_size(Size2(0, 0));
- grabber->set_position(get_global_position() + grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5);
+ grabber->set_position(get_global_position() + (grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5) * scale);
if (mousewheel_over_grabber) {
Input::get_singleton()->warp_mouse_position(grabber->get_position() + grabber_rect.size);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 030d36ff78..9aad1aa8d9 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -241,20 +241,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
// Generate icons.
if (!p_only_thumbs) {
for (int i = 0; i < editor_icons_count; i++) {
- float icon_scale = EDSCALE;
float saturation = p_icon_saturation;
- // Always keep the DefaultProjectIcon at the default size
- if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
- icon_scale = 1.0f;
- }
-
if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0 || strcmp(editor_icons_names[i], "Godot") == 0 || strcmp(editor_icons_names[i], "Logo") == 0) {
saturation = 1.0;
}
const int is_exception = exceptions.has(editor_icons_names[i]);
- const Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception, icon_scale, saturation);
+ const Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception, EDSCALE, saturation);
p_theme->set_icon(editor_icons_names[i], "EditorIcons", icon);
}
@@ -1398,3 +1392,15 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
return theme;
}
+
+Ref<ImageTexture> create_unscaled_default_project_icon() {
+#ifdef MODULE_SVG_ENABLED
+ for (int i = 0; i < editor_icons_count; i++) {
+ // ESCALE should never affect size of the icon
+ if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
+ return editor_generate_icon(i, false, 1.0);
+ }
+ }
+#endif
+ return Ref<ImageTexture>(memnew(ImageTexture));
+}
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 852edf7669..c040654220 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -31,10 +31,13 @@
#ifndef EDITOR_THEMES_H
#define EDITOR_THEMES_H
+#include "scene/resources/texture.h"
#include "scene/resources/theme.h"
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
+Ref<ImageTexture> create_unscaled_default_project_icon();
+
#endif
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index ab5fd30998..772eff5f45 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -945,7 +945,25 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
}
} else if (fpath != "Favorites") {
if (ResourceLoader::get_resource_type(fpath) == "PackedScene") {
- editor->open_request(fpath);
+ bool is_imported = false;
+
+ {
+ List<String> importer_exts;
+ ResourceImporterScene::get_singleton()->get_recognized_extensions(&importer_exts);
+ String extension = fpath.get_extension();
+ for (List<String>::Element *E = importer_exts.front(); E; E = E->next()) {
+ if (extension.nocasecmp_to(E->get())) {
+ is_imported = true;
+ break;
+ }
+ }
+ }
+
+ if (is_imported) {
+ ResourceImporterScene::get_singleton()->show_advanced_options(fpath);
+ } else {
+ editor->open_request(fpath);
+ }
} else {
editor->load_resource(fpath);
}
@@ -2718,7 +2736,22 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
// `KEY_MASK_CMD | KEY_C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D);
+
+#if defined(WINDOWS_ENABLED)
+ // TRANSLATORS: This string is only used on Windows, as it refers to the system trash
+ // as "Recycle Bin" instead of "Trash". Make sure to use the translation of "Recycle Bin"
+ // recommended by Microsoft for the target language.
+ ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Recycle Bin"), KEY_DELETE);
+#elif defined(OSX_ENABLED)
+ // TRANSLATORS: This string is only used on macOS, as it refers to the system trash
+ // as "Bin" instead of "Trash". Make sure to use the translation of "Bin"
+ // recommended by Apple for the target language.
+ ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Bin"), KEY_DELETE);
+#else
+ // TRANSLATORS: This string is only used on platforms other than Windows and macOS.
ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Trash"), KEY_DELETE);
+#endif
+
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), KEY_F2);
VBoxContainer *top_vbc = memnew(VBoxContainer);
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 50b13673fa..080393e570 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -79,6 +79,9 @@ struct ColladaImport {
Vector<int> valid_animated_properties;
Map<String, bool> bones_with_animation;
+ Set<String> mesh_unique_names;
+ Set<String> material_unique_names;
+
Error _populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
Error _create_scene_skeletons(Collada::Node *p_node);
Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
@@ -326,12 +329,25 @@ Error ColladaImport::_create_material(const String &p_target) {
Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ String base_name;
if (src_mat.name != "") {
- material->set_name(src_mat.name);
+ base_name = src_mat.name;
} else if (effect.name != "") {
- material->set_name(effect.name);
+ base_name = effect.name;
+ } else {
+ base_name = "Material";
}
+ String name = base_name;
+ int counter = 2;
+ while (material_unique_names.has(name)) {
+ name = base_name + itos(counter++);
+ }
+
+ material_unique_names.insert(name);
+
+ material->set_name(name);
+
// DIFFUSE
if (effect.diffuse.texture != "") {
@@ -681,7 +697,8 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
int vertex_index = p.indices[src + vertex_ofs]; //used for index field (later used by controllers)
int vertex_pos = (vertex_src->stride ? vertex_src->stride : 3) * vertex_index;
- ERR_FAIL_INDEX_V(vertex_pos, vertex_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(vertex_pos + 0, vertex_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(vertex_pos + 2, vertex_src->array.size(), ERR_INVALID_DATA);
vertex.vertex = Vector3(vertex_src->array[vertex_pos + 0], vertex_src->array[vertex_pos + 1], vertex_src->array[vertex_pos + 2]);
if (pre_weights.has(vertex_index)) {
@@ -690,16 +707,19 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
if (normal_src) {
int normal_pos = (normal_src->stride ? normal_src->stride : 3) * p.indices[src + normal_ofs];
- ERR_FAIL_INDEX_V(normal_pos, normal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(normal_pos + 0, normal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(normal_pos + 2, normal_src->array.size(), ERR_INVALID_DATA);
vertex.normal = Vector3(normal_src->array[normal_pos + 0], normal_src->array[normal_pos + 1], normal_src->array[normal_pos + 2]);
if (tangent_src && binormal_src) {
int binormal_pos = (binormal_src->stride ? binormal_src->stride : 3) * p.indices[src + binormal_ofs];
- ERR_FAIL_INDEX_V(binormal_pos, binormal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(binormal_pos + 0, binormal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(binormal_pos + 2, binormal_src->array.size(), ERR_INVALID_DATA);
Vector3 binormal = Vector3(binormal_src->array[binormal_pos + 0], binormal_src->array[binormal_pos + 1], binormal_src->array[binormal_pos + 2]);
int tangent_pos = (tangent_src->stride ? tangent_src->stride : 3) * p.indices[src + tangent_ofs];
- ERR_FAIL_INDEX_V(tangent_pos, tangent_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(tangent_pos + 0, tangent_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(tangent_pos + 2, tangent_src->array.size(), ERR_INVALID_DATA);
Vector3 tangent = Vector3(tangent_src->array[tangent_pos + 0], tangent_src->array[tangent_pos + 1], tangent_src->array[tangent_pos + 2]);
vertex.tangent.normal = tangent;
@@ -709,19 +729,22 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
if (uv_src) {
int uv_pos = (uv_src->stride ? uv_src->stride : 2) * p.indices[src + uv_ofs];
- ERR_FAIL_INDEX_V(uv_pos, uv_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv_pos + 0, uv_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv_pos + 1, uv_src->array.size(), ERR_INVALID_DATA);
vertex.uv = Vector3(uv_src->array[uv_pos + 0], 1.0 - uv_src->array[uv_pos + 1], 0);
}
if (uv2_src) {
int uv2_pos = (uv2_src->stride ? uv2_src->stride : 2) * p.indices[src + uv2_ofs];
- ERR_FAIL_INDEX_V(uv2_pos, uv2_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv2_pos + 0, uv2_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv2_pos + 1, uv2_src->array.size(), ERR_INVALID_DATA);
vertex.uv2 = Vector3(uv2_src->array[uv2_pos + 0], 1.0 - uv2_src->array[uv2_pos + 1], 0);
}
if (color_src) {
int color_pos = (color_src->stride ? color_src->stride : 3) * p.indices[src + color_ofs]; // colors are RGB in collada..
- ERR_FAIL_INDEX_V(color_pos, color_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(color_pos + 0, color_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(color_pos + ((color_src->stride > 3) ? 3 : 2), color_src->array.size(), ERR_INVALID_DATA);
vertex.color = Color(color_src->array[color_pos + 0], color_src->array[color_pos + 1], color_src->array[color_pos + 2], (color_src->stride > 3) ? color_src->array[color_pos + 3] : 1.0);
}
@@ -1121,7 +1144,22 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
- mesh->set_name(meshdata.name);
+ String name = meshdata.name;
+ if (name == "") {
+ name = "Mesh";
+ }
+ int counter = 2;
+ while (mesh_unique_names.has(name)) {
+ name = meshdata.name;
+ if (name == "") {
+ name = "Mesh";
+ }
+ name += itos(counter++);
+ }
+
+ mesh_unique_names.insert(name);
+
+ mesh->set_name(name);
Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials);
ERR_FAIL_COND_V_MSG(err, err, "Cannot create mesh surface.");
@@ -1638,16 +1676,23 @@ void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) cons
}
Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+ if (r_err) {
+ *r_err = OK;
+ }
ColladaImport state;
uint32_t flags = Collada::IMPORT_FLAG_SCENE;
if (p_flags & IMPORT_ANIMATION) {
flags |= Collada::IMPORT_FLAG_ANIMATION;
}
- state.use_mesh_builtin_materials = !(p_flags & IMPORT_MATERIALS_IN_INSTANCES);
+ state.use_mesh_builtin_materials = true;
state.bake_fps = p_bake_fps;
- Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & EditorSceneImporter::IMPORT_USE_COMPRESSION);
+ Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 0);
+
+ if (r_err) {
+ *r_err = err;
+ }
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
@@ -1667,7 +1712,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
}
if (p_flags & IMPORT_ANIMATION) {
- state.create_animations(p_flags & IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
+ state.create_animations(true, true);
AnimationPlayer *ap = memnew(AnimationPlayer);
for (int i = 0; i < state.animations.size(); i++) {
String name;
@@ -1677,12 +1722,6 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
name = state.animations[i]->get_name();
}
- if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
- if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
- state.animations.write[i]->set_loop(true);
- }
- }
-
ap->add_animation(name, state.animations[i]);
}
state.scene->add_child(ap);
@@ -1700,7 +1739,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
- state.create_animations(p_flags & EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
+ state.create_animations(true, true);
if (state.scene) {
memdelete(state.scene);
}
@@ -1709,12 +1748,6 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
return Ref<Animation>();
}
Ref<Animation> anim = state.animations[0];
- String base = p_path.get_basename().to_lower();
- if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
- if (base.begins_with("loop") || base.ends_with("loop") || base.begins_with("cycle") || base.ends_with("cycle")) {
- anim->set_loop(true);
- }
- }
return anim;
}
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 9111252943..5c522e3176 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -427,7 +427,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
List<Ref<Mesh>> meshes;
- Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
+ Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, 0, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
if (err != OK) {
if (r_err) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 14ecccc13e..4eba609c0d 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -32,7 +32,9 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
+#include "editor/import/scene_import_settings.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/area_3d.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
@@ -111,20 +113,14 @@ void EditorSceneImporter::_bind_methods() {
BIND_CONSTANT(IMPORT_SCENE);
BIND_CONSTANT(IMPORT_ANIMATION);
- BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP);
- BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE);
- BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
- BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
- BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
- BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES);
- BIND_CONSTANT(IMPORT_USE_COMPRESSION);
+ BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
+ BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS);
}
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
- ClassDB::bind_method(D_METHOD("get_source_folder"), &EditorScenePostImport::get_source_folder);
ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
}
@@ -136,16 +132,11 @@ Node *EditorScenePostImport::post_import(Node *p_scene) {
return p_scene;
}
-String EditorScenePostImport::get_source_folder() const {
- return source_folder;
-}
-
String EditorScenePostImport::get_source_file() const {
return source_file;
}
-void EditorScenePostImport::init(const String &p_source_folder, const String &p_source_file) {
- source_folder = p_source_folder;
+void EditorScenePostImport::init(const String &p_source_file) {
source_file = p_source_file;
}
@@ -183,29 +174,9 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
}
-
- if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0) {
- return false;
- }
-
- if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
- return false;
- }
-
- if (p_option.begins_with("animation/clip_")) {
- int max_clip = p_options["animation/clips/amount"];
- int clip = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
- if (clip >= max_clip) {
- return false;
- }
- }
- }
-
- if (p_option == "materials/keep_on_reimport" && int(p_options["materials/storage"]) == 0) {
- return false;
}
- if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
+ if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 3) {
return false;
}
@@ -213,34 +184,11 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
}
int ResourceImporterScene::get_preset_count() const {
- return PRESET_MAX;
+ return 0;
}
String ResourceImporterScene::get_preset_name(int p_idx) const {
- switch (p_idx) {
- case PRESET_SINGLE_SCENE:
- return TTR("Import as Single Scene");
- case PRESET_SEPARATE_ANIMATIONS:
- return TTR("Import with Separate Animations");
- case PRESET_SEPARATE_MATERIALS:
- return TTR("Import with Separate Materials");
- case PRESET_SEPARATE_MESHES:
- return TTR("Import with Separate Objects");
- case PRESET_SEPARATE_MESHES_AND_MATERIALS:
- return TTR("Import with Separate Objects+Materials");
- case PRESET_SEPARATE_MESHES_AND_ANIMATIONS:
- return TTR("Import with Separate Objects+Animations");
- case PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS:
- return TTR("Import with Separate Materials+Animations");
- case PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS:
- return TTR("Import with Separate Objects+Materials+Animations");
- case PRESET_MULTIPLE_SCENES:
- return TTR("Import as Multiple Scenes");
- case PRESET_MULTIPLE_SCENES_AND_MATERIALS:
- return TTR("Import as Multiple Scenes+Materials");
- }
-
- return "";
+ return String();
}
static bool _teststr(const String &p_what, const String &p_str) {
@@ -299,10 +247,24 @@ static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_l
}
}
-Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode) {
+static void _pre_gen_shape_list(const Ref<EditorSceneImporterMesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+ if (!p_convex) {
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ r_shape_list.push_back(shape);
+ } else {
+ Vector<Ref<Shape3D>> cd = mesh->convex_decompose();
+ if (cd.size()) {
+ for (int i = 0; i < cd.size(); i++) {
+ r_shape_list.push_back(cd[i]);
+ }
+ }
+ }
+}
+
+Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *r = _fix_node(p_node->get_child(i), p_root, collision_map, p_light_bake_mode);
+ Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map);
if (!r) {
i--; //was erased
}
@@ -317,33 +279,29 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return nullptr;
}
- if (Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> m = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
if (m.is_valid()) {
for (int i = 0; i < m->get_surface_count(); i++) {
- Ref<StandardMaterial3D> mat = m->surface_get_material(i);
+ Ref<BaseMaterial3D> mat = m->get_surface_material(i);
if (!mat.is_valid()) {
continue;
}
if (_teststr(mat->get_name(), "alpha")) {
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ mat->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
mat->set_name(_fixstr(mat->get_name(), "alpha"));
}
if (_teststr(mat->get_name(), "vcol")) {
- mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ mat->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(BaseMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
mat->set_name(_fixstr(mat->get_name(), "vcol"));
}
}
}
-
- if (p_light_bake_mode != LIGHT_BAKE_DISABLED) {
- mi->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
- }
}
if (Object::cast_to<AnimationPlayer>(p_node)) {
@@ -367,6 +325,17 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
}
+
+ String animname = E->get();
+ const int loop_string_count = 3;
+ static const char *loop_strings[loop_string_count] = { "loops", "loop", "cycle" };
+ for (int i = 0; i < loop_string_count; i++) {
+ if (_teststr(animname, loop_strings[i])) {
+ anim->set_loop(true);
+ animname = _fixstr(animname, loop_strings[i]);
+ ap->rename_animation(E->get(), animname);
+ }
+ }
}
}
@@ -374,9 +343,9 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (mi) {
- Ref<Mesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -384,10 +353,10 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(name, "colonly")) {
- _gen_shape_list(mesh, shapes, false);
+ _pre_gen_shape_list(mesh, shapes, false);
collision_map[mesh] = shapes;
} else if (_teststr(name, "convcolonly")) {
- _gen_shape_list(mesh, shapes, true);
+ _pre_gen_shape_list(mesh, shapes, true);
collision_map[mesh] = shapes;
}
@@ -413,7 +382,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
cshape->set_shape(E->get());
col->add_child(cshape);
- cshape->set_name("shape" + itos(idx));
cshape->set_owner(col->get_owner());
idx++;
}
@@ -433,34 +401,30 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
BoxShape3D *boxShape = memnew(BoxShape3D);
boxShape->set_size(Vector3(2, 2, 2));
colshape->set_shape(boxShape);
- colshape->set_name("BoxShape3D");
} else if (empty_draw_type == "SINGLE_ARROW") {
RayShape3D *rayShape = memnew(RayShape3D);
rayShape->set_length(1);
colshape->set_shape(rayShape);
- colshape->set_name("RayShape3D");
Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
} else if (empty_draw_type == "IMAGE") {
WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
colshape->set_shape(world_margin_shape);
- colshape->set_name("WorldMarginShape3D");
} else {
SphereShape3D *sphereShape = memnew(SphereShape3D);
sphereShape->set_radius(1);
colshape->set_shape(sphereShape);
- colshape->set_name("SphereShape3D");
}
sb->add_child(colshape);
colshape->set_owner(sb->get_owner());
}
- } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (_teststr(name, "rigid") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
- Ref<Mesh> mesh = mi->get_mesh();
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -475,7 +439,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
p_node = rigid_body;
- mi->set_name("mesh");
mi->set_transform(Transform());
rigid_body->add_child(mi);
mi->set_owner(rigid_body->get_owner());
@@ -486,16 +449,15 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
cshape->set_shape(E->get());
rigid_body->add_child(cshape);
- cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
}
}
- } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<Mesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -524,7 +486,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (shapes.size()) {
StaticBody3D *col = memnew(StaticBody3D);
- col->set_name("static_collision");
mi->add_child(col);
col->set_owner(mi->get_owner());
@@ -534,7 +495,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
cshape->set_shape(E->get());
col->add_child(cshape);
- cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
@@ -542,71 +502,31 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
- } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (_teststr(name, "navmesh") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
ERR_FAIL_COND_V(mesh.is_null(), nullptr);
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
nmi->set_name(_fixstr(name, "navmesh"));
- Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
- nmesh->create_from_mesh(mesh);
+ Ref<NavigationMesh> nmesh = mesh->create_navigation_mesh();
nmi->set_navigation_mesh(nmesh);
Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
p_node->replace_by(nmi);
memdelete(p_node);
p_node = nmi;
- } else if (_teststr(name, "vehicle")) {
- if (isroot) {
- return p_node;
- }
-
- Node *owner = p_node->get_owner();
- Node3D *s = Object::cast_to<Node3D>(p_node);
- VehicleBody3D *bv = memnew(VehicleBody3D);
- String n = _fixstr(p_node->get_name(), "vehicle");
- bv->set_name(n);
- p_node->replace_by(bv);
- p_node->set_name(n);
- bv->add_child(p_node);
- bv->set_owner(owner);
- p_node->set_owner(owner);
- bv->set_transform(s->get_transform());
- s->set_transform(Transform());
-
- p_node = bv;
-
- } else if (_teststr(name, "wheel")) {
- if (isroot) {
- return p_node;
- }
- Node *owner = p_node->get_owner();
- Node3D *s = Object::cast_to<Node3D>(p_node);
- VehicleWheel3D *bv = memnew(VehicleWheel3D);
- String n = _fixstr(p_node->get_name(), "wheel");
- bv->set_name(n);
- p_node->replace_by(bv);
- p_node->set_name(n);
- bv->add_child(p_node);
- bv->set_owner(owner);
- p_node->set_owner(owner);
- bv->set_transform(s->get_transform());
- s->set_transform(Transform());
-
- p_node = bv;
-
- } else if (Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
@@ -623,7 +543,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (shapes.size()) {
StaticBody3D *col = memnew(StaticBody3D);
- col->set_name("static_collision");
p_node->add_child(col);
col->set_owner(p_node->get_owner());
@@ -633,7 +552,6 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
cshape->set_shape(E->get());
col->add_child(cshape);
- cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
}
@@ -644,27 +562,311 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return p_node;
}
-void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, bool p_bake_all) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
+Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
+ // children first
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps);
+ if (!r) {
+ i--; //was erased
+ }
+ }
+
+ bool isroot = p_node == p_root;
+
+ String import_id;
+
+ if (p_node->has_meta("import_id")) {
+ import_id = p_node->get_meta("import_id");
+ } else {
+ import_id = "PATH:" + p_root->get_path_to(p_node);
+ }
+
+ Dictionary node_settings;
+ if (p_node_data.has(import_id)) {
+ node_settings = p_node_data[import_id];
+ }
+
+ if (!isroot && (node_settings.has("import/skip_import") && bool(node_settings["import/skip_import"]))) {
+ memdelete(p_node);
+ return nullptr;
+ }
+
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+
+ if (m.is_valid()) {
+ if (!r_scanned_meshes.has(m)) {
+ for (int i = 0; i < m->get_surface_count(); i++) {
+ Ref<Material> mat = m->get_surface_material(i);
+ if (mat.is_valid()) {
+ String mat_id;
+ if (mat->has_meta("import_id")) {
+ mat_id = mat->get_meta("import_id");
+ } else {
+ mat_id = mat->get_name();
+ }
+
+ if (mat_id != String() && p_material_data.has(mat_id)) {
+ Dictionary matdata = p_material_data[mat_id];
+ if (matdata.has("use_external/enabled") && bool(matdata["use_external/enabled"]) && matdata.has("use_external/path")) {
+ String path = matdata["use_external/path"];
+ Ref<Material> external_mat = ResourceLoader::load(path);
+ if (external_mat.is_valid()) {
+ m->set_surface_material(i, external_mat);
+ }
+ }
+ }
+ }
+ }
+
+ r_scanned_meshes.insert(m);
+ }
+
+ if (node_settings.has("generate/physics")) {
+ int mesh_physics_mode = node_settings["generate/physics"];
+
+ if (mesh_physics_mode != MESH_PHYSICS_DISABLED) {
+ List<Ref<Shape3D>> shapes;
+
+ if (collision_map.has(m)) {
+ shapes = collision_map[m];
+ } else {
+ switch (mesh_physics_mode) {
+ case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: {
+ _pre_gen_shape_list(m, shapes, false);
+ } break;
+ case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
+ _pre_gen_shape_list(m, shapes, true);
+ } break;
+ case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
+ _pre_gen_shape_list(m, shapes, false);
+ } break;
+ case MESH_PHYSICS_AREA_ONLY: {
+ _pre_gen_shape_list(m, shapes, true);
+ } break;
+ }
+ }
+
+ if (shapes.size()) {
+ CollisionObject3D *base = nullptr;
+ switch (mesh_physics_mode) {
+ case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: {
+ StaticBody3D *col = memnew(StaticBody3D);
+ p_node->add_child(col);
+ base = col;
+ } break;
+ case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
+ rigid_body->set_name(p_node->get_name());
+ p_node->replace_by(rigid_body);
+ rigid_body->set_transform(mi->get_transform());
+ p_node = rigid_body;
+ mi->set_transform(Transform());
+ rigid_body->add_child(mi);
+ mi->set_owner(rigid_body->get_owner());
+ base = rigid_body;
+ } break;
+ case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
+ StaticBody3D *col = memnew(StaticBody3D);
+ col->set_transform(mi->get_transform());
+ col->set_name(p_node->get_name());
+ p_node->replace_by(col);
+ memdelete(p_node);
+ p_node = col;
+ base = col;
+ } break;
+ case MESH_PHYSICS_AREA_ONLY: {
+ Area3D *area = memnew(Area3D);
+ area->set_transform(mi->get_transform());
+ area->set_name(p_node->get_name());
+ p_node->replace_by(area);
+ memdelete(p_node);
+ p_node = area;
+ base = area;
+
+ } break;
+ }
+
+ int idx = 0;
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(E->get());
+ base->add_child(cshape);
+
+ cshape->set_owner(base->get_owner());
+ idx++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //navmesh (node may have changed type above)
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+
+ if (m.is_valid()) {
+ if (node_settings.has("generate/navmesh")) {
+ int navmesh_mode = node_settings["generate/navmesh"];
+
+ if (navmesh_mode != NAVMESH_DISABLED) {
+ NavigationRegion3D *nmi = memnew(NavigationRegion3D);
+
+ Ref<NavigationMesh> nmesh = m->create_navigation_mesh();
+ nmi->set_navigation_mesh(nmesh);
+
+ if (navmesh_mode == NAVMESH_NAVMESH_ONLY) {
+ nmi->set_transform(mi->get_transform());
+ p_node->replace_by(nmi);
+ memdelete(p_node);
+ p_node = nmi;
+ } else {
+ mi->add_child(nmi);
+ nmi->set_owner(mi->get_owner());
+ }
+ }
+ }
+ }
+ }
+
+ if (Object::cast_to<AnimationPlayer>(p_node)) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+
+ {
+ //make sure this is unique
+ node_settings = node_settings.duplicate(true);
+ //fill node settings for this node with default values
+ List<ImportOption> iopts;
+ get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
+ for (List<ImportOption>::Element *E = iopts.front(); E; E = E->next()) {
+ if (!node_settings.has(E->get().option.name)) {
+ node_settings[E->get().option.name] = E->get().default_value;
+ }
+ }
+ }
+
+ bool use_optimizer = node_settings["optimizer/enabled"];
+ float anim_optimizer_linerr = node_settings["optimizer/max_linear_error"];
+ float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"];
+ float anim_optimizer_maxang = node_settings["optimizer/max_angle"];
+
+ if (use_optimizer) {
+ _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
+ }
+
+ Array animation_clips;
+ {
+ int clip_count = node_settings["clips/amount"];
+
+ for (int i = 0; i < clip_count; i++) {
+ String name = node_settings["clip_" + itos(i + 1) + "/name"];
+ int from_frame = node_settings["clip_" + itos(i + 1) + "/start_frame"];
+ int end_frame = node_settings["clip_" + itos(i + 1) + "/end_frame"];
+ bool loop = node_settings["clip_" + itos(i + 1) + "/loops"];
+ bool save_to_file = node_settings["clip_" + itos(i + 1) + "/save_to_file/enabled"];
+ bool save_to_path = node_settings["clip_" + itos(i + 1) + "/save_to_file/path"];
+ bool save_to_file_keep_custom = node_settings["clip_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
+
+ animation_clips.push_back(name);
+ animation_clips.push_back(from_frame / p_animation_fps);
+ animation_clips.push_back(end_frame / p_animation_fps);
+ animation_clips.push_back(loop);
+ animation_clips.push_back(save_to_file);
+ animation_clips.push_back(save_to_path);
+ animation_clips.push_back(save_to_file_keep_custom);
+ }
+ }
+
+ if (animation_clips.size()) {
+ _create_clips(ap, animation_clips, true);
+ } else {
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
+ String name = E->get();
+ Ref<Animation> anim = ap->get_animation(name);
+ if (p_animation_data.has(name)) {
+ Dictionary anim_settings = p_animation_data[name];
+ {
+ //fill with default values
+ List<ImportOption> iopts;
+ get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION, &iopts);
+ for (List<ImportOption>::Element *F = iopts.front(); F; F = F->next()) {
+ if (!anim_settings.has(F->get().option.name)) {
+ anim_settings[F->get().option.name] = F->get().default_value;
+ }
+ }
+ }
+
+ anim->set_loop(anim_settings["settings/loops"]);
+ bool save = anim_settings["save_to_file/enabled"];
+ String path = anim_settings["save_to_file/path"];
+ bool keep_custom = anim_settings["save_to_file/keep_custom_tracks"];
+
+ Ref<Animation> saved_anim = _save_animation_to_file(anim, save, path, keep_custom);
+
+ if (saved_anim != anim) {
+ ap->add_animation(name, saved_anim); //replace
+ }
+ }
+ }
+ }
}
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
+ return p_node;
+}
+
+Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks) {
+ if (!p_save_to_file || !p_save_to_path.is_resource_file()) {
+ return anim;
+ }
+
+ if (FileAccess::exists(p_save_to_path) && p_keep_custom_tracks) {
+ // Copy custom animation tracks from previously imported files.
+ Ref<Animation> old_anim = ResourceLoader::load(p_save_to_path, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ if (old_anim.is_valid()) {
+ for (int i = 0; i < old_anim->get_track_count(); i++) {
+ if (!old_anim->track_is_imported(i)) {
+ old_anim->copy_track(i, anim);
+ }
+ }
+ anim->set_loop(old_anim->has_loop());
+ }
+ }
+ if (ResourceCache::has(p_save_to_path)) {
+ Ref<Animation> old_anim = Ref<Resource>(ResourceCache::get(p_save_to_path));
+ if (old_anim.is_valid()) {
+ old_anim->copy_from(anim);
+ anim = old_anim;
+ }
+ }
+ anim->set_path(p_save_to_path, true); // Set path to save externally.
+ Error err = ResourceSaver::save(p_save_to_path, anim, ResourceSaver::FLAG_CHANGE_PATH);
+ ERR_FAIL_COND_V_MSG(err != OK, anim, "Saving of animation failed: " + p_save_to_path);
+ return anim;
+}
+
+void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all) {
if (!anim->has_animation("default")) {
return;
}
Ref<Animation> default_anim = anim->get_animation("default");
- for (int i = 0; i < p_clips.size(); i += 4) {
+ for (int i = 0; i < p_clips.size(); i += 7) {
String name = p_clips[i];
float from = p_clips[i + 1];
float to = p_clips[i + 2];
bool loop = p_clips[i + 3];
+ bool save_to_file = p_clips[i + 4];
+ String save_to_path = p_clips[i + 5];
+ bool keep_current = p_clips[i + 6];
if (from >= to) {
continue;
}
@@ -752,141 +954,17 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
new_anim->set_loop(loop);
new_anim->set_length(to - from);
anim->add_animation(name, new_anim);
- }
-
- anim->remove_animation("default"); //remove default (no longer needed)
-}
-
-void ResourceImporterScene::_filter_anim_tracks(Ref<Animation> anim, Set<String> &keep) {
- Ref<Animation> a = anim;
- ERR_FAIL_COND(!a.is_valid());
- for (int j = 0; j < a->get_track_count(); j++) {
- String path = a->track_get_path(j);
-
- if (!keep.has(path)) {
- a->remove_track(j);
- j--;
+ Ref<Animation> saved_anim = _save_animation_to_file(new_anim, save_to_file, save_to_path, keep_current);
+ if (saved_anim != new_anim) {
+ anim->add_animation(name, saved_anim);
}
}
-}
-
-void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
- }
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
-
- Vector<String> strings = p_text.split("\n");
- for (int i = 0; i < strings.size(); i++) {
- strings.write[i] = strings[i].strip_edges();
- }
-
- List<StringName> anim_names;
- anim->get_animation_list(&anim_names);
- for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
- String name = E->get();
- bool valid_for_this = false;
- bool valid = false;
-
- Set<String> keep;
- Set<String> keep_local;
-
- for (int i = 0; i < strings.size(); i++) {
- if (strings[i].begins_with("@")) {
- valid_for_this = false;
- for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
- keep.insert(F->get());
- }
- keep_local.clear();
- Vector<String> filters = strings[i].substr(1, strings[i].length()).split(",");
- for (int j = 0; j < filters.size(); j++) {
- String fname = filters[j].strip_edges();
- if (fname == "") {
- continue;
- }
- int fc = fname[0];
- bool plus;
- if (fc == '+') {
- plus = true;
- } else if (fc == '-') {
- plus = false;
- } else {
- continue;
- }
-
- String filter = fname.substr(1, fname.length()).strip_edges();
-
- if (!name.matchn(filter)) {
- continue;
- }
- valid_for_this = plus;
- }
-
- if (valid_for_this) {
- valid = true;
- }
-
- } else if (valid_for_this) {
- Ref<Animation> a = anim->get_animation(name);
- if (!a.is_valid()) {
- continue;
- }
-
- for (int j = 0; j < a->get_track_count(); j++) {
- String path = a->track_get_path(j);
-
- String tname = strings[i];
- if (tname == "") {
- continue;
- }
- int fc = tname[0];
- bool plus;
- if (fc == '+') {
- plus = true;
- } else if (fc == '-') {
- plus = false;
- } else {
- continue;
- }
-
- String filter = tname.substr(1, tname.length()).strip_edges();
-
- if (!path.matchn(filter)) {
- continue;
- }
-
- if (plus) {
- keep_local.insert(path);
- } else if (!keep.has(path)) {
- keep_local.erase(path);
- }
- }
- }
- }
-
- if (valid) {
- for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
- keep.insert(F->get());
- }
- _filter_anim_tracks(anim->get_animation(name), keep);
- }
- }
+ anim->remove_animation("default"); //remove default (no longer needed)
}
-void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
- }
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
-
+void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
@@ -895,208 +973,99 @@ void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_er
}
}
-static String _make_extname(const String &p_str) {
- String ext_name = p_str.replace(".", "_");
- ext_name = ext_name.replace(":", "_");
- ext_name = ext_name.replace("\"", "_");
- ext_name = ext_name.replace("<", "_");
- ext_name = ext_name.replace(">", "_");
- ext_name = ext_name.replace("/", "_");
- ext_name = ext_name.replace("|", "_");
- ext_name = ext_name.replace("\\", "_");
- ext_name = ext_name.replace("?", "_");
- ext_name = ext_name.replace("*", "_");
-
- return ext_name;
-}
-
-void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
- List<PropertyInfo> pi;
- p_node->get_property_list(&pi);
-
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
-
- if (mi) {
- Ref<ArrayMesh> mesh = mi->get_mesh();
-
- if (mesh.is_valid() && !meshes.has(mesh)) {
- Node3D *s = mi;
- Transform transform;
- while (s) {
- transform = transform * s->get_transform();
- s = Object::cast_to<Node3D>(s->get_parent());
+void ResourceImporterScene::get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const {
+ switch (p_category) {
+ case INTERNAL_IMPORT_CATEGORY_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/physics", PROPERTY_HINT_ENUM, "Disabled,Mesh + Static Collider,Rigid Body + Mesh,Static Collider Only,Area Only"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/navmesh", PROPERTY_HINT_ENUM, "Disabled,Mesh + NavMesh,NavMesh Only"), 0));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/make_streamable"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "settings/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+
+ for (int i = 0; i < 256; i++) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
}
-
- meshes[mesh] = transform;
+ } break;
+ default: {
}
}
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _find_meshes(p_node->get_child(i), meshes);
- }
}
-void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes) {
- List<PropertyInfo> pi;
-
- if (p_make_animations) {
- if (Object::cast_to<AnimationPlayer>(p_node)) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
-
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
- Ref<Animation> anim = ap->get_animation(E->get());
- ERR_CONTINUE(anim.is_null());
-
- if (!p_animations.has(anim)) {
- // Tracks from source file should be set as imported, anything else is a custom track.
- for (int i = 0; i < anim->get_track_count(); i++) {
- anim->track_set_imported(i, true);
- }
-
- String ext_name;
-
- if (p_animations_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim");
- }
-
- if (FileAccess::exists(ext_name) && p_keep_animations) {
- // Copy custom animation tracks from previously imported files.
- Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
- if (old_anim.is_valid()) {
- for (int i = 0; i < old_anim->get_track_count(); i++) {
- if (!old_anim->track_is_imported(i)) {
- old_anim->copy_track(i, anim);
- }
- }
- anim->set_loop(old_anim->has_loop());
- }
- }
-
- anim->set_path(ext_name, true); // Set path to save externally.
- ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
- p_animations[anim] = anim;
- }
+bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const {
+ if (p_options.has("import/skip_import") && p_option != "import/skip_import" && bool(p_options["import/skip_import"])) {
+ return false; //if skip import
+ }
+ switch (p_category) {
+ case INTERNAL_IMPORT_CATEGORY_NODE: {
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH: {
+ if (p_option == "save_to_file/path" || p_option == "save_to_file/make_streamable") {
+ return p_options["save_to_file/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
+ if (p_option == "use_external/path") {
+ return p_options["use_external/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
+ if (p_option == "save_to_file/path" || p_option == "save_to_file/keep_custom_tracks") {
+ return p_options["save_to_file/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
+ if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
+ return false;
}
- }
- }
-
- p_node->get_property_list(&pi);
-
- for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
- if (E->get().type == Variant::OBJECT) {
- Ref<Material> mat = p_node->get(E->get().name);
-
- if (p_make_materials && mat.is_valid() && mat->get_name() != "") {
- if (!p_materials.has(mat)) {
- String ext_name;
-
- if (p_materials_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
- }
-
- if (p_keep_materials && FileAccess::exists(ext_name)) {
- //if exists, use it
- p_materials[mat] = ResourceLoader::load(ext_name);
- } else {
- ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
- p_materials[mat] = ResourceLoader::load(ext_name, "", ResourceFormatLoader::CACHE_MODE_IGNORE); // disable loading from the cache.
- }
- }
-
- if (p_materials[mat] != mat) {
- p_node->set(E->get().name, p_materials[mat]);
- }
- } else {
- Ref<ArrayMesh> mesh = p_node->get(E->get().name);
-
- if (mesh.is_valid()) {
- bool mesh_just_added = false;
-
- if (p_make_meshes) {
- if (!p_meshes.has(mesh)) {
- //meshes are always overwritten, keeping them is not practical
- String ext_name;
-
- if (p_meshes_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
- }
-
- ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
- p_meshes[mesh] = ResourceLoader::load(ext_name);
- p_node->set(E->get().name, p_meshes[mesh]);
- mesh_just_added = true;
- }
- }
-
- if (p_make_materials) {
- if (mesh_just_added || !p_meshes.has(mesh)) {
- for (int i = 0; i < mesh->get_surface_count(); i++) {
- mat = mesh->surface_get_material(i);
-
- if (!mat.is_valid()) {
- continue;
- }
- if (mat->get_name() == "") {
- continue;
- }
-
- if (!p_materials.has(mat)) {
- String ext_name;
-
- if (p_materials_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
- }
-
- if (p_keep_materials && FileAccess::exists(ext_name)) {
- //if exists, use it
- p_materials[mat] = ResourceLoader::load(ext_name);
- } else {
- ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
- p_materials[mat] = ResourceLoader::load(ext_name, "", ResourceFormatLoader::CACHE_MODE_IGNORE); // disable loading from the cache.
- }
- }
-
- if (p_materials[mat] != mat) {
- mesh->surface_set_material(i, p_materials[mat]);
-
- //re-save the mesh since a material is now assigned
- if (p_make_meshes) {
- String ext_name;
-
- if (p_meshes_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
- }
-
- ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
- p_meshes[mesh] = ResourceLoader::load(ext_name);
- }
- }
- }
- if (!p_make_meshes) {
- p_meshes[mesh] = Ref<ArrayMesh>(); //save it anyway, so it won't be checked again
- }
- }
- }
+ if (p_option.begins_with("animation/slice_")) {
+ int max_slice = p_options["animation/slices/amount"];
+ int slice = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
+ if (slice >= max_slice) {
+ return false;
}
}
+ } break;
+ default: {
}
}
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_animations_as_text, p_keep_animations, p_make_materials, p_materials_as_text, p_keep_materials, p_make_meshes, p_meshes_as_text, p_animations, p_materials, p_meshes);
- }
+ return true;
}
void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, int p_preset) const {
@@ -1115,42 +1084,18 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
script_ext_hint += "*." + E->get();
}
- bool materials_out = p_preset == PRESET_SEPARATE_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
- bool meshes_out = p_preset == PRESET_SEPARATE_MESHES || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
- bool scenes_out = p_preset == PRESET_MULTIPLE_SCENES || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS;
- bool animations_out = p_preset == PRESET_SEPARATE_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
-
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/custom_script", PROPERTY_HINT_FILE, script_ext_hint), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "nodes/storage", PROPERTY_HINT_ENUM, "Single Scene,Instanced Sub-Scenes"), scenes_out ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), (meshes_out || materials_out) ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.material),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), materials_out ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "materials/keep_on_reimport"), materials_out));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Dynamic,Static,Static Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 2));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.anim),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_linear_error"), 0.05));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angular_error"), 0.01));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angle"), 22));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/remove_unused_tracks"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clips/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
- for (int i = 0; i < 256; i++) {
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/clip_" + itos(i + 1) + "/name"), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/start_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/end_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/clip_" + itos(i + 1) + "/loops"), false));
- }
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), Dictionary()));
}
void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner) {
@@ -1222,7 +1167,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
-void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes) {
+void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache) {
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (src_mesh_node) {
//is mesh
@@ -1235,14 +1180,94 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods,
Ref<ArrayMesh> mesh;
if (!src_mesh_node->get_mesh()->has_mesh()) {
//do mesh processing
- if (p_generate_lods) {
+
+ bool generate_lods = p_generate_lods;
+ bool create_shadow_meshes = p_create_shadow_meshes;
+ bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
+ String save_to_file;
+
+ String mesh_id;
+
+ if (src_mesh_node->get_mesh()->has_meta("import_id")) {
+ mesh_id = src_mesh_node->get_mesh()->get_meta("import_id");
+ } else {
+ mesh_id = src_mesh_node->get_mesh()->get_name();
+ }
+
+ if (mesh_id != String() && p_mesh_data.has(mesh_id)) {
+ Dictionary mesh_settings = p_mesh_data[mesh_id];
+
+ if (mesh_settings.has("generate/shadow_meshes")) {
+ int shadow_meshes = mesh_settings["generate/shadow_meshes"];
+ if (shadow_meshes == MESH_OVERRIDE_ENABLE) {
+ create_shadow_meshes = true;
+ } else if (shadow_meshes == MESH_OVERRIDE_DISABLE) {
+ create_shadow_meshes = false;
+ }
+ }
+
+ if (mesh_settings.has("generate/lightmap_uv")) {
+ int lightmap_uv = mesh_settings["generate/lightmap_uv"];
+ if (lightmap_uv == MESH_OVERRIDE_ENABLE) {
+ bake_lightmaps = true;
+ } else if (lightmap_uv == MESH_OVERRIDE_DISABLE) {
+ bake_lightmaps = false;
+ }
+ }
+
+ if (mesh_settings.has("generate/lods")) {
+ int lods = mesh_settings["generate/lods"];
+ if (lods == MESH_OVERRIDE_ENABLE) {
+ generate_lods = true;
+ } else if (lods == MESH_OVERRIDE_DISABLE) {
+ generate_lods = false;
+ }
+ }
+
+ if (mesh_settings.has("save_to_file/enabled") && bool(mesh_settings["save_to_file/enabled"]) && mesh_settings.has("save_to_file/path")) {
+ save_to_file = mesh_settings["save_to_file/path"];
+ if (!save_to_file.is_resource_file()) {
+ save_to_file = "";
+ }
+ }
+ }
+
+ if (generate_lods) {
src_mesh_node->get_mesh()->generate_lods();
}
- if (p_create_shadow_meshes) {
+ if (create_shadow_meshes) {
src_mesh_node->get_mesh()->create_shadow_mesh();
}
+
+ if (bake_lightmaps) {
+ Transform xf;
+ Node3D *n = src_mesh_node;
+ while (n) {
+ xf = n->get_transform() * xf;
+ n = n->get_parent_spatial();
+ }
+
+ //use xf as transform for mesh, and bake it
+ }
+
+ if (save_to_file != String()) {
+ Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file));
+ if (existing.is_valid()) {
+ //if somehow an existing one is useful, create
+ existing->reset_state();
+ }
+ mesh = src_mesh_node->get_mesh()->get_mesh(existing);
+
+ ResourceSaver::save(save_to_file, mesh); //override
+
+ mesh->set_path(save_to_file, true); //takeover existing, if needed
+
+ } else {
+ mesh = src_mesh_node->get_mesh()->get_mesh();
+ }
+ } else {
+ mesh = src_mesh_node->get_mesh()->get_mesh();
}
- mesh = src_mesh_node->get_mesh()->get_mesh();
if (mesh.is_valid()) {
mesh_node->set_mesh(mesh);
@@ -1251,15 +1276,68 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods,
}
}
}
+
+ switch (p_light_bake_mode) {
+ case LIGHT_BAKE_DISABLED: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DISABLED);
+ } break;
+ case LIGHT_BAKE_DYNAMIC: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DYNAMIC);
+ } break;
+ case LIGHT_BAKE_STATIC:
+ case LIGHT_BAKE_STATIC_LIGHTMAPS: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
+ } break;
+ }
+
p_node->replace_by(mesh_node);
memdelete(p_node);
p_node = mesh_node;
}
for (int i = 0; i < p_node->get_child_count(); i++) {
- _generate_meshes(p_node->get_child(i), p_generate_lods, p_create_shadow_meshes);
+ _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_dst_lightmap_cache);
}
}
+
+Node *ResourceImporterScene::pre_import(const String &p_source_file) {
+ Ref<EditorSceneImporter> importer;
+ String ext = p_source_file.get_extension().to_lower();
+
+ EditorProgress progress("pre-import", TTR("Pre-Import Scene"), 0);
+ progress.step(TTR("Importing Scene..."), 0);
+
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
+ List<String> extensions;
+ E->get()->get_extensions(&extensions);
+
+ for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
+ if (F->get().to_lower() == ext) {
+ importer = E->get();
+ break;
+ }
+ }
+
+ if (importer.is_valid()) {
+ break;
+ }
+ }
+
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
+
+ Error err;
+ Node *scene = importer->import_scene(p_source_file, EditorSceneImporter::IMPORT_ANIMATION | EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 15, nullptr, &err);
+ if (!scene || err != OK) {
+ return nullptr;
+ }
+
+ Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> collision_map;
+
+ _pre_fix_node(scene, scene, collision_map);
+
+ return scene;
+}
+
Error ResourceImporterScene::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) {
const String &src_path = p_source_file;
@@ -1289,27 +1367,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float fps = p_options["animation/fps"];
- int import_flags = EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP;
- if (!bool(p_options["animation/optimizer/remove_unused_tracks"])) {
- import_flags |= EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS;
- }
+ int import_flags = 0;
if (bool(p_options["animation/import"])) {
import_flags |= EditorSceneImporter::IMPORT_ANIMATION;
}
- if (bool(p_options["meshes/ensure_tangents"])) {
- import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
- }
-
- if (int(p_options["materials/location"]) == 0) {
- import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
- }
-
if (bool(p_options["skins/use_named_skins"])) {
import_flags |= EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
}
+ bool ensure_tangents = p_options["meshes/ensure_tangents"];
+ if (ensure_tangents) {
+ import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
+ }
+
Error err = OK;
List<String> missing_deps; // for now, not much will be done with this
Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err);
@@ -1317,6 +1389,29 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return err;
}
+ Dictionary subresources = p_options["_subresources"];
+
+ Dictionary node_data;
+ if (subresources.has("nodes")) {
+ node_data = subresources["nodes"];
+ }
+
+ Dictionary material_data;
+ if (subresources.has("materials")) {
+ material_data = subresources["materials"];
+ }
+
+ Dictionary animation_data;
+ if (subresources.has("animations")) {
+ animation_data = subresources["animations"];
+ }
+
+ Set<Ref<EditorSceneImporterMesh>> scanned_meshes;
+ Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> collision_map;
+
+ _pre_fix_node(scene, scene, collision_map);
+ _post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);
+
String root_type = p_options["nodes/root_type"];
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
@@ -1354,73 +1449,35 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
bool gen_lods = bool(p_options["meshes/generate_lods"]);
bool create_shadow_meshes = bool(p_options["meshes/create_shadow_meshes"]);
-
- _generate_meshes(scene, gen_lods, create_shadow_meshes);
-
- err = OK;
-
- String animation_filter = String(p_options["animation/filter_script"]).strip_edges();
-
- bool use_optimizer = p_options["animation/optimizer/enabled"];
- float anim_optimizer_linerr = p_options["animation/optimizer/max_linear_error"];
- float anim_optimizer_angerr = p_options["animation/optimizer/max_angular_error"];
- float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
int light_bake_mode = p_options["meshes/light_baking"];
+ float texel_size = p_options["meshes/lightmap_texel_size"];
+ float lightmap_texel_size = MAX(0.001, texel_size);
- Map<Ref<Mesh>, List<Ref<Shape3D>>> collision_map;
+ Vector<uint8_t> src_lightmap_cache;
+ Vector<uint8_t> dst_lightmap_cache;
- scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));
-
- if (use_optimizer) {
- _optimize_animations(scene, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
- }
-
- Array animation_clips;
{
- int clip_count = p_options["animation/clips/amount"];
-
- for (int i = 0; i < clip_count; i++) {
- String name = p_options["animation/clip_" + itos(i + 1) + "/name"];
- int from_frame = p_options["animation/clip_" + itos(i + 1) + "/start_frame"];
- int end_frame = p_options["animation/clip_" + itos(i + 1) + "/end_frame"];
- bool loop = p_options["animation/clip_" + itos(i + 1) + "/loops"];
-
- animation_clips.push_back(name);
- animation_clips.push_back(from_frame / fps);
- animation_clips.push_back(end_frame / fps);
- animation_clips.push_back(loop);
+ src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err);
+ if (err != OK) {
+ src_lightmap_cache.clear();
}
}
- if (animation_clips.size()) {
- _create_clips(scene, animation_clips, !bool(p_options["animation/optimizer/remove_unused_tracks"]));
- }
- if (animation_filter != "") {
- _filter_tracks(scene, animation_filter);
+ Dictionary mesh_data;
+ if (subresources.has("meshes")) {
+ mesh_data = subresources["meshes"];
}
+ _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, dst_lightmap_cache);
- bool external_animations = int(p_options["animation/storage"]) == 1 || int(p_options["animation/storage"]) == 2;
- bool external_animations_as_text = int(p_options["animation/storage"]) == 2;
- bool keep_custom_tracks = p_options["animation/keep_custom_tracks"];
- bool external_materials = int(p_options["materials/storage"]) == 1 || int(p_options["materials/storage"]) == 2;
- bool external_materials_as_text = int(p_options["materials/storage"]) == 2;
- bool external_meshes = int(p_options["meshes/storage"]) == 1 || int(p_options["meshes/storage"]) == 2;
- bool external_meshes_as_text = int(p_options["meshes/storage"]) == 2;
- bool external_scenes = int(p_options["nodes/storage"]) == 1;
-
- String base_path = p_source_file.get_base_dir();
-
- if (external_animations || external_materials || external_meshes || external_scenes) {
- if (bool(p_options["external_files/store_in_subdir"])) {
- String subdir_name = p_source_file.get_file().get_basename();
- DirAccess *da = DirAccess::open(base_path);
- Error err2 = da->make_dir(subdir_name);
- memdelete(da);
- ERR_FAIL_COND_V_MSG(err2 != OK && err2 != ERR_ALREADY_EXISTS, err2, "Cannot make directory '" + subdir_name + "'.");
- base_path = base_path.plus_file(subdir_name);
+ if (dst_lightmap_cache.size()) {
+ FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
+ if (f) {
+ f->store_buffer(dst_lightmap_cache.ptr(), dst_lightmap_cache.size());
}
}
+ err = OK;
+#if 0
if (light_bake_mode == 2 /* || generate LOD */) {
Map<Ref<ArrayMesh>, Transform> meshes;
_find_meshes(scene, meshes);
@@ -1445,9 +1502,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
}
- float texel_size = p_options["meshes/lightmap_texel_size"];
- texel_size = MAX(0.001, texel_size);
-
Map<String, unsigned int> used_unwraps;
EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
@@ -1469,7 +1523,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (err2 != OK) {
EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
} else {
- String hash = String::md5((unsigned char *)ret_cache_data);
+` String hash = String::md5((unsigned char *)ret_cache_data);
used_unwraps.insert(hash, ret_cache_size);
if (!ret_used_cache) {
@@ -1482,7 +1536,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
} else {
int current_size = cache_data.size();
cache_data.resize(cache_data.size() + ret_cache_size);
- unsigned char *ptrw = cache_data.ptrw();
+ unsigned char *ptrw = cache_data.ptrw();
memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
int *data = (int *)ptrw;
data[0] += 1;
@@ -1530,20 +1584,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
file->close();
}
}
-
- if (external_animations || external_materials || external_meshes) {
- Map<Ref<Animation>, Ref<Animation>> anim_map;
- Map<Ref<Material>, Ref<Material>> mat_map;
- Map<Ref<ArrayMesh>, Ref<ArrayMesh>> mesh_map;
-
- bool keep_materials = bool(p_options["materials/keep_on_reimport"]);
-
- _make_external_resources(scene, base_path, external_animations, external_animations_as_text, keep_custom_tracks, external_materials, external_materials_as_text, keep_materials, external_meshes, external_meshes_as_text, anim_map, mat_map, mesh_map);
- }
+#endif
progress.step(TTR("Running Custom Script..."), 2);
- String post_import_script_path = p_options["nodes/custom_script"];
+ String post_import_script_path = p_options["import_script/path"];
Ref<EditorScenePostImport> post_import_script;
if (post_import_script_path != "") {
@@ -1562,7 +1607,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
if (post_import_script.is_valid()) {
- post_import_script->init(base_path, p_source_file);
+ post_import_script->init(p_source_file);
scene = post_import_script->post_import(scene);
if (!scene) {
EditorNode::add_io_error(
@@ -1574,29 +1619,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
progress.step(TTR("Saving..."), 104);
- if (external_scenes) {
- //save sub-scenes as instances!
- for (int i = 0; i < scene->get_child_count(); i++) {
- Node *child = scene->get_child(i);
- if (child->get_owner() != scene) {
- continue; //not a real child probably created by scene type (ig, a scrollbar)
- }
- _replace_owner(child, scene, child);
-
- String cn = String(child->get_name()).strip_edges().replace(".", "_").replace(":", "_");
- if (cn == String()) {
- cn = "ChildNode" + itos(i);
- }
- String path = base_path.plus_file(cn + ".scn");
- child->set_filename(path);
-
- Ref<PackedScene> packer = memnew(PackedScene);
- packer->pack(child);
- err = ResourceSaver::save(path, packer); //do not take over, let the changed files reload themselves
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + path + "'.");
- }
- }
-
Ref<PackedScene> packer = memnew(PackedScene);
packer->pack(scene);
print_verbose("Saving scene to: " + p_save_path + ".scn");
@@ -1613,6 +1635,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
+bool ResourceImporterScene::ResourceImporterScene::has_advanced_options() const {
+ return true;
+}
+void ResourceImporterScene::ResourceImporterScene::show_advanced_options(const String &p_path) {
+ SceneImportSettings::get_singleton()->open_settings(p_path);
+}
+
ResourceImporterScene::ResourceImporterScene() {
singleton = this;
}
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index aced0226ff..36573779f2 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -39,7 +39,9 @@
#include "scene/resources/skin.h"
class Material;
+class AnimationPlayer;
+class EditorSceneImporterMesh;
class EditorSceneImporter : public Reference {
GDCLASS(EditorSceneImporter, Reference);
@@ -53,15 +55,9 @@ public:
enum ImportFlags {
IMPORT_SCENE = 1,
IMPORT_ANIMATION = 2,
- IMPORT_ANIMATION_DETECT_LOOP = 4,
- IMPORT_ANIMATION_OPTIMIZE = 8,
- IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS = 16,
- IMPORT_ANIMATION_KEEP_VALUE_TRACKS = 32,
- IMPORT_GENERATE_TANGENT_ARRAYS = 256,
- IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
- IMPORT_MATERIALS_IN_INSTANCES = 1024,
- IMPORT_USE_COMPRESSION = 2048,
- IMPORT_USE_NAMED_SKIN_BINDS = 4096,
+ IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4,
+ IMPORT_GENERATE_TANGENT_ARRAYS = 8,
+ IMPORT_USE_NAMED_SKIN_BINDS = 16,
};
@@ -76,17 +72,15 @@ public:
class EditorScenePostImport : public Reference {
GDCLASS(EditorScenePostImport, Reference);
- String source_folder;
String source_file;
protected:
static void _bind_methods();
public:
- String get_source_folder() const;
String get_source_file() const;
virtual Node *post_import(Node *p_scene);
- virtual void init(const String &p_source_folder, const String &p_source_file);
+ virtual void init(const String &p_source_file);
EditorScenePostImport();
};
@@ -97,31 +91,35 @@ class ResourceImporterScene : public ResourceImporter {
static ResourceImporterScene *singleton;
- enum Presets {
- PRESET_SEPARATE_MATERIALS,
- PRESET_SEPARATE_MESHES,
- PRESET_SEPARATE_ANIMATIONS,
-
- PRESET_SINGLE_SCENE,
+ enum LightBakeMode {
+ LIGHT_BAKE_DISABLED,
+ LIGHT_BAKE_DYNAMIC,
+ LIGHT_BAKE_STATIC,
+ LIGHT_BAKE_STATIC_LIGHTMAPS
+ };
- PRESET_SEPARATE_MESHES_AND_MATERIALS,
- PRESET_SEPARATE_MESHES_AND_ANIMATIONS,
- PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS,
- PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS,
+ enum MeshPhysicsMode {
+ MESH_PHYSICS_DISABLED,
+ MESH_PHYSICS_MESH_AND_STATIC_COLLIDER,
+ MESH_PHYSICS_RIGID_BODY_AND_MESH,
+ MESH_PHYSICS_STATIC_COLLIDER_ONLY,
+ MESH_PHYSICS_AREA_ONLY,
+ };
- PRESET_MULTIPLE_SCENES,
- PRESET_MULTIPLE_SCENES_AND_MATERIALS,
- PRESET_MAX
+ enum NavMeshMode {
+ NAVMESH_DISABLED,
+ NAVMESH_MESH_AND_NAVMESH,
+ NAVMESH_NAVMESH_ONLY,
};
- enum LightBakeMode {
- LIGHT_BAKE_DISABLED,
- LIGHT_BAKE_ENABLE,
- LIGHT_BAKE_LIGHTMAPS
+ enum MeshOverride {
+ MESH_OVERRIDE_DEFAULT,
+ MESH_OVERRIDE_ENABLE,
+ MESH_OVERRIDE_DISABLE,
};
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
- void _generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes);
+ void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache);
public:
static ResourceImporterScene *get_singleton() { return singleton; }
@@ -141,26 +139,39 @@ public:
virtual int get_preset_count() const override;
virtual String get_preset_name(int p_idx) const override;
+ enum InternalImportCategory {
+ INTERNAL_IMPORT_CATEGORY_NODE,
+ INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE,
+ INTERNAL_IMPORT_CATEGORY_MESH,
+ INTERNAL_IMPORT_CATEGORY_MATERIAL,
+ INTERNAL_IMPORT_CATEGORY_ANIMATION,
+ INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE,
+ INTERNAL_IMPORT_CATEGORY_MAX
+ };
+
+ void get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const;
+ bool get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
+
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 int get_import_order() const override { return 100; } //after everything
- void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
+ Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map);
+ Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
- void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes);
-
- Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode);
-
- void _create_clips(Node *scene, const Array &p_clips, bool p_bake_all);
- void _filter_anim_tracks(Ref<Animation> anim, Set<String> &keep);
- void _filter_tracks(Node *scene, const String &p_text);
- void _optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
+ void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
+ void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ Node *pre_import(const String &p_source_file);
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;
Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
+ virtual bool has_advanced_options() const override;
+ virtual void show_advanced_options(const String &p_path) override;
+
ResourceImporterScene();
};
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
new file mode 100644
index 0000000000..5ae67f413a
--- /dev/null
+++ b/editor/import/scene_import_settings.cpp
@@ -0,0 +1,1199 @@
+/*************************************************************************/
+/* scene_import_settings.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "scene_import_settings.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/resources/surface_tool.h"
+
+class SceneImportSettingsData : public Object {
+ GDCLASS(SceneImportSettingsData, Object)
+ friend class SceneImportSettings;
+ Map<StringName, Variant> *settings = nullptr;
+ Map<StringName, Variant> current;
+ Map<StringName, Variant> defaults;
+ List<ResourceImporter::ImportOption> options;
+
+ ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
+
+ bool _set(const StringName &p_name, const Variant &p_value) {
+ if (settings) {
+ if (defaults.has(p_name) && defaults[p_name] == p_value) {
+ settings->erase(p_name);
+ } else {
+ (*settings)[p_name] = p_value;
+ }
+
+ current[p_name] = p_value;
+ return true;
+ }
+ return false;
+ }
+ bool _get(const StringName &p_name, Variant &r_ret) const {
+ if (settings) {
+ if (settings->has(p_name)) {
+ r_ret = (*settings)[p_name];
+ return true;
+ }
+ }
+ if (defaults.has(p_name)) {
+ r_ret = defaults[p_name];
+ return true;
+ }
+ return false;
+ }
+ void _get_property_list(List<PropertyInfo> *p_list) const {
+ for (const List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ if (ResourceImporterScene::get_singleton()->get_internal_option_visibility(category, E->get().option.name, current)) {
+ p_list->push_back(E->get().option);
+ }
+ }
+ }
+};
+
+void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent) {
+ String import_id;
+ bool has_import_id = false;
+
+ if (p_material->has_meta("import_id")) {
+ import_id = p_material->get_meta("import_id");
+ has_import_id = true;
+ } else if (p_material->get_name() != "") {
+ import_id = p_material->get_name();
+ has_import_id = true;
+ } else {
+ import_id = "@MATERIAL:" + itos(material_set.size());
+ }
+
+ if (!material_map.has(import_id)) {
+ MaterialData md;
+ md.has_import_id = has_import_id;
+ md.material = p_material;
+
+ _load_default_subresource_settings(md.settings, "materials", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL);
+
+ material_map[import_id] = md;
+ }
+
+ MaterialData &material_data = material_map[import_id];
+
+ Ref<Texture2D> icon = get_theme_icon("StandardMaterial3D", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_material->get_name());
+ item->set_icon(0, icon);
+
+ bool created = false;
+ if (!material_set.has(p_material)) {
+ material_set.insert(p_material);
+ created = true;
+ }
+
+ item->set_meta("type", "Material");
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_selectable(0, true);
+
+ if (p_tree == scene_tree) {
+ material_data.scene_node = item;
+ } else if (p_tree == mesh_tree) {
+ material_data.mesh_node = item;
+ } else {
+ material_data.material_node = item;
+ }
+
+ if (created) {
+ _fill_material(material_tree, p_material, material_tree->get_root());
+ }
+}
+
+void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent) {
+ String import_id;
+
+ bool has_import_id = false;
+ if (p_mesh->has_meta("import_id")) {
+ import_id = p_mesh->get_meta("import_id");
+ has_import_id = true;
+ } else if (p_mesh->get_name() != String()) {
+ import_id = p_mesh->get_name();
+ has_import_id = true;
+ } else {
+ import_id = "@MESH:" + itos(mesh_set.size());
+ }
+
+ if (!mesh_map.has(import_id)) {
+ MeshData md;
+ md.has_import_id = has_import_id;
+ md.mesh = p_mesh;
+
+ _load_default_subresource_settings(md.settings, "meshes", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH);
+
+ mesh_map[import_id] = md;
+ }
+
+ MeshData &mesh_data = mesh_map[import_id];
+
+ Ref<Texture2D> icon = get_theme_icon("Mesh", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_mesh->get_name());
+ item->set_icon(0, icon);
+
+ bool created = false;
+ if (!mesh_set.has(p_mesh)) {
+ mesh_set.insert(p_mesh);
+ created = true;
+ }
+
+ item->set_meta("type", "Mesh");
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+
+ item->set_selectable(0, true);
+
+ if (p_tree == scene_tree) {
+ mesh_data.scene_node = item;
+ } else {
+ mesh_data.mesh_node = item;
+ }
+
+ item->set_collapsed(true);
+
+ for (int i = 0; i < p_mesh->get_surface_count(); i++) {
+ Ref<Material> mat = p_mesh->surface_get_material(i);
+ if (mat.is_valid()) {
+ _fill_material(p_tree, mat, item);
+ }
+ }
+
+ if (created) {
+ _fill_mesh(mesh_tree, p_mesh, mesh_tree->get_root());
+ }
+}
+
+void SceneImportSettings::_fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent) {
+ if (!animation_map.has(p_name)) {
+ AnimationData ad;
+ ad.animation = p_anim;
+
+ _load_default_subresource_settings(ad.settings, "animations", p_name, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION);
+
+ animation_map[p_name] = ad;
+ }
+
+ AnimationData &animation_data = animation_map[p_name];
+
+ Ref<Texture2D> icon = get_theme_icon("Animation", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_name);
+ item->set_icon(0, icon);
+
+ item->set_meta("type", "Animation");
+ item->set_meta("import_id", p_name);
+
+ item->set_selectable(0, true);
+
+ animation_data.scene_node = item;
+}
+
+void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
+ String import_id;
+
+ if (p_node->has_meta("import_id")) {
+ import_id = p_node->get_meta("import_id");
+ } else {
+ import_id = "PATH:" + String(scene->get_path_to(p_node));
+ p_node->set_meta("import_id", import_id);
+ }
+
+ EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+
+ if (src_mesh_node) {
+ MeshInstance3D *mesh_node = memnew(MeshInstance3D);
+ mesh_node->set_name(src_mesh_node->get_name());
+ mesh_node->set_transform(src_mesh_node->get_transform());
+ mesh_node->set_skin(src_mesh_node->get_skin());
+ mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
+ if (src_mesh_node->get_mesh().is_valid()) {
+ Ref<EditorSceneImporterMesh> editor_mesh = src_mesh_node->get_mesh();
+ mesh_node->set_mesh(editor_mesh->get_mesh());
+ }
+
+ p_node->replace_by(mesh_node);
+ memdelete(p_node);
+ p_node = mesh_node;
+ }
+
+ String type = p_node->get_class();
+
+ if (!has_theme_icon(type, "EditorIcons")) {
+ type = "Node3D";
+ }
+
+ Ref<Texture2D> icon = get_theme_icon(type, "EditorIcons");
+
+ TreeItem *item = scene_tree->create_item(p_parent_item);
+ item->set_text(0, p_node->get_name());
+
+ if (p_node == scene) {
+ icon = get_theme_icon("PackedScene", "EditorIcons");
+ item->set_text(0, "Scene");
+ }
+
+ item->set_icon(0, icon);
+
+ item->set_meta("type", "Node");
+ item->set_meta("class", type);
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
+
+ item->set_selectable(0, true);
+
+ if (!node_map.has(import_id)) {
+ NodeData nd;
+
+ if (p_node != scene) {
+ ResourceImporterScene::InternalImportCategory category;
+ if (src_mesh_node) {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
+ } else if (Object::cast_to<AnimationPlayer>(p_node)) {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
+ } else {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
+ }
+
+ _load_default_subresource_settings(nd.settings, "nodes", import_id, category);
+ }
+
+ node_map[import_id] = nd;
+ }
+ NodeData &node_data = node_map[import_id];
+
+ node_data.node = p_node;
+ node_data.scene_node = item;
+
+ AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node);
+ if (anim_node) {
+ List<StringName> animations;
+ anim_node->get_animation_list(&animations);
+ for (List<StringName>::Element *E = animations.front(); E; E = E->next()) {
+ _fill_animation(scene_tree, anim_node->get_animation(E->get()), E->get(), item);
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _fill_scene(p_node->get_child(i), item);
+ }
+ MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
+ if (mesh_node && mesh_node->get_mesh().is_valid()) {
+ _fill_mesh(scene_tree, mesh_node->get_mesh(), item);
+
+ Transform accum_xform;
+ Node3D *base = mesh_node;
+ while (base) {
+ accum_xform = base->get_transform() * accum_xform;
+ base = Object::cast_to<Node3D>(base->get_parent());
+ }
+
+ AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
+ if (first_aabb) {
+ contents_aabb = aabb;
+ first_aabb = false;
+ } else {
+ contents_aabb.merge_with(aabb);
+ }
+ }
+}
+
+void SceneImportSettings::_update_scene() {
+ scene_tree->clear();
+ material_tree->clear();
+ mesh_tree->clear();
+
+ //hiden roots
+ material_tree->create_item();
+ mesh_tree->create_item();
+
+ _fill_scene(scene, nullptr);
+}
+
+void SceneImportSettings::_update_camera() {
+ AABB camera_aabb;
+
+ float rot_x = cam_rot_x;
+ float rot_y = cam_rot_y;
+ float zoom = cam_zoom;
+
+ if (selected_type == "Node" || selected_type == "") {
+ camera_aabb = contents_aabb;
+ } else {
+ if (mesh_preview->get_mesh().is_valid()) {
+ camera_aabb = mesh_preview->get_transform().xform(mesh_preview->get_mesh()->get_aabb());
+ } else {
+ camera_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ }
+ if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
+ const MeshData &md = mesh_map[selected_id];
+ rot_x = md.cam_rot_x;
+ rot_y = md.cam_rot_y;
+ zoom = md.cam_zoom;
+ } else if (selected_type == "Material" && material_map.has(selected_id)) {
+ const MaterialData &md = material_map[selected_id];
+ rot_x = md.cam_rot_x;
+ rot_y = md.cam_rot_y;
+ zoom = md.cam_zoom;
+ }
+ }
+
+ Vector3 center = camera_aabb.position + camera_aabb.size * 0.5;
+ float camera_size = camera_aabb.get_longest_axis_size();
+
+ camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);
+
+ Transform xf;
+ xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x);
+ xf.origin = center;
+ xf.translate(0, 0, camera_size);
+
+ camera->set_transform(xf);
+}
+
+void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category) {
+ if (base_subresource_settings.has(p_type)) {
+ Dictionary d = base_subresource_settings[p_type];
+ if (d.has(p_import_id)) {
+ d = d[p_import_id];
+ List<ResourceImporterScene::ImportOption> options;
+ ResourceImporterScene::get_singleton()->get_internal_import_options(p_category, &options);
+ for (List<ResourceImporterScene::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ String key = E->get().option.name;
+ if (d.has(key)) {
+ settings[key] = d[key];
+ }
+ }
+ }
+ }
+}
+
+void SceneImportSettings::open_settings(const String &p_path) {
+ if (scene) {
+ memdelete(scene);
+ scene = nullptr;
+ }
+ scene = ResourceImporterScene::get_singleton()->pre_import(p_path);
+ if (scene == nullptr) {
+ EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
+ return;
+ }
+
+ base_path = p_path;
+
+ material_set.clear();
+ mesh_set.clear();
+ material_map.clear();
+ mesh_map.clear();
+ node_map.clear();
+ defaults.clear();
+
+ selected_id = "";
+ selected_type = "";
+
+ cam_rot_x = -Math_PI / 4;
+ cam_rot_y = -Math_PI / 4;
+ cam_zoom = 1;
+
+ {
+ base_subresource_settings.clear();
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(p_path + ".import");
+ if (err == OK) {
+ List<String> keys;
+ config->get_section_keys("params", &keys);
+ for (List<String>::Element *E = keys.front(); E; E = E->next()) {
+ Variant value = config->get_value("params", E->get());
+ if (E->get() == "_subresources") {
+ base_subresource_settings = value;
+ } else {
+ defaults[E->get()] = value;
+ }
+ }
+ }
+ }
+
+ first_aabb = true;
+
+ _update_scene();
+
+ base_viewport->add_child(scene);
+
+ if (first_aabb) {
+ contents_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ first_aabb = false;
+ }
+
+ popup_centered_ratio();
+ _update_camera();
+
+ set_title(vformat(TTR("Advanced Import Settings for '%s'"), base_path.get_file()));
+}
+
+SceneImportSettings *SceneImportSettings::singleton = nullptr;
+
+SceneImportSettings *SceneImportSettings::get_singleton() {
+ return singleton;
+}
+
+void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
+ selecting = true;
+
+ if (p_type == "Node") {
+ node_selected->hide(); //always hide just in case
+ mesh_preview->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->show();
+ }
+ //NodeData &nd=node_map[p_id];
+ material_tree->deselect_all();
+ mesh_tree->deselect_all();
+ NodeData &nd = node_map[p_id];
+
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(nd.node);
+ if (mi) {
+ Ref<Mesh> base_mesh = mi->get_mesh();
+ if (base_mesh.is_valid()) {
+ AABB aabb = base_mesh->get_aabb();
+ Transform aabb_xf;
+ aabb_xf.basis.scale(aabb.size);
+ aabb_xf.origin = aabb.position;
+
+ aabb_xf = mi->get_global_transform() * aabb_xf;
+ node_selected->set_transform(aabb_xf);
+ node_selected->show();
+ }
+ }
+
+ if (nd.node == scene) {
+ scene_import_settings_data->settings = &defaults;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
+ } else {
+ scene_import_settings_data->settings = &nd.settings;
+ if (mi) {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
+ } else if (Object::cast_to<AnimationPlayer>(nd.node)) {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
+ } else {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
+ }
+ }
+ } else if (p_type == "Animation") {
+ node_selected->hide(); //always hide just in case
+ mesh_preview->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->show();
+ }
+ //NodeData &nd=node_map[p_id];
+ material_tree->deselect_all();
+ mesh_tree->deselect_all();
+ AnimationData &ad = animation_map[p_id];
+
+ scene_import_settings_data->settings = &ad.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
+ } else if (p_type == "Mesh") {
+ node_selected->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->hide();
+ }
+
+ MeshData &md = mesh_map[p_id];
+ if (p_from != mesh_tree) {
+ md.mesh_node->uncollapse_tree();
+ md.mesh_node->select(0);
+ mesh_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != scene_tree) {
+ md.scene_node->uncollapse_tree();
+ md.scene_node->select(0);
+ scene_tree->ensure_cursor_is_visible();
+ }
+
+ mesh_preview->set_mesh(md.mesh);
+ mesh_preview->show();
+
+ material_tree->deselect_all();
+
+ scene_import_settings_data->settings = &md.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH;
+ } else if (p_type == "Material") {
+ node_selected->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->hide();
+ }
+
+ mesh_preview->show();
+
+ MaterialData &md = material_map[p_id];
+
+ material_preview->set_material(md.material);
+ mesh_preview->set_mesh(material_preview);
+
+ if (p_from != mesh_tree) {
+ md.mesh_node->uncollapse_tree();
+ md.mesh_node->select(0);
+ mesh_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != scene_tree) {
+ md.scene_node->uncollapse_tree();
+ md.scene_node->select(0);
+ scene_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != material_tree) {
+ md.material_node->uncollapse_tree();
+ md.material_node->select(0);
+ material_tree->ensure_cursor_is_visible();
+ }
+
+ scene_import_settings_data->settings = &md.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL;
+ }
+
+ selected_type = p_type;
+ selected_id = p_id;
+
+ selecting = false;
+
+ _update_camera();
+
+ List<ResourceImporter::ImportOption> options;
+
+ if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
+ ResourceImporterScene::get_singleton()->get_import_options(&options);
+ } else {
+ ResourceImporterScene::get_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
+ }
+
+ scene_import_settings_data->defaults.clear();
+ scene_import_settings_data->current.clear();
+
+ for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ scene_import_settings_data->defaults[E->get().option.name] = E->get().default_value;
+ //needed for visibility toggling (fails if something is missing)
+ if (scene_import_settings_data->settings->has(E->get().option.name)) {
+ scene_import_settings_data->current[E->get().option.name] = (*scene_import_settings_data->settings)[E->get().option.name];
+ } else {
+ scene_import_settings_data->current[E->get().option.name] = E->get().default_value;
+ }
+ }
+ scene_import_settings_data->options = options;
+ inspector->edit(scene_import_settings_data);
+ scene_import_settings_data->notify_property_list_changed();
+}
+
+void SceneImportSettings::_material_tree_selected() {
+ if (selecting) {
+ return;
+ }
+ TreeItem *item = material_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(material_tree, type, import_id);
+}
+void SceneImportSettings::_mesh_tree_selected() {
+ if (selecting) {
+ return;
+ }
+
+ TreeItem *item = mesh_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(mesh_tree, type, import_id);
+}
+void SceneImportSettings::_scene_tree_selected() {
+ if (selecting) {
+ return;
+ }
+ TreeItem *item = scene_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(scene_tree, type, import_id);
+}
+
+void SceneImportSettings::_viewport_input(const Ref<InputEvent> &p_input) {
+ float *rot_x = &cam_rot_x;
+ float *rot_y = &cam_rot_y;
+ float *zoom = &cam_zoom;
+
+ if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
+ MeshData &md = mesh_map[selected_id];
+ rot_x = &md.cam_rot_x;
+ rot_y = &md.cam_rot_y;
+ zoom = &md.cam_zoom;
+ } else if (selected_type == "Material" && material_map.has(selected_id)) {
+ MaterialData &md = material_map[selected_id];
+ rot_x = &md.cam_rot_x;
+ rot_y = &md.cam_rot_y;
+ zoom = &md.cam_zoom;
+ }
+ Ref<InputEventMouseMotion> mm = p_input;
+ if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ (*rot_x) -= mm->get_relative().y * 0.01 * EDSCALE;
+ (*rot_y) -= mm->get_relative().x * 0.01 * EDSCALE;
+ (*rot_x) = CLAMP((*rot_x), -Math_PI / 2, Math_PI / 2);
+ _update_camera();
+ }
+ Ref<InputEventMouseButton> mb = p_input;
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ (*zoom) *= 1.1;
+ if ((*zoom) > 10.0) {
+ (*zoom) = 10.0;
+ }
+ _update_camera();
+ }
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ (*zoom) /= 1.1;
+ if ((*zoom) < 0.1) {
+ (*zoom) = 0.1;
+ }
+ _update_camera();
+ }
+}
+
+void SceneImportSettings::_re_import() {
+ Map<StringName, Variant> main_settings;
+
+ main_settings = defaults;
+ main_settings.erase("_subresources");
+ Dictionary nodes;
+ Dictionary materials;
+ Dictionary meshes;
+ Dictionary animations;
+
+ Dictionary subresources;
+
+ for (Map<String, NodeData>::Element *E = node_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ nodes[E->key()] = d;
+ }
+ }
+ if (nodes.size()) {
+ subresources["nodes"] = nodes;
+ }
+
+ for (Map<String, MaterialData>::Element *E = material_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ materials[E->key()] = d;
+ }
+ }
+ if (materials.size()) {
+ subresources["materials"] = materials;
+ }
+
+ for (Map<String, MeshData>::Element *E = mesh_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ meshes[E->key()] = d;
+ }
+ }
+ if (meshes.size()) {
+ subresources["meshes"] = meshes;
+ }
+
+ for (Map<String, AnimationData>::Element *E = animation_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ animations[E->key()] = d;
+ }
+ }
+ if (animations.size()) {
+ subresources["animations"] = animations;
+ }
+
+ if (subresources.size()) {
+ main_settings["_subresources"] = subresources;
+ }
+
+ EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, "scene", main_settings);
+}
+
+void SceneImportSettings::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ connect("confirmed", callable_mp(this, &SceneImportSettings::_re_import));
+ }
+}
+
+void SceneImportSettings::_menu_callback(int p_id) {
+ switch (p_id) {
+ case ACTION_EXTRACT_MATERIALS: {
+ save_path->set_text(TTR("Select folder to extract material resources"));
+ external_extension_type->select(0);
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ save_path->set_text(TTR("Select folder where mesh resources will save on import"));
+ external_extension_type->select(1);
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ save_path->set_text(TTR("Select folder where animations will save on import"));
+ external_extension_type->select(1);
+ } break;
+ }
+
+ save_path->set_current_dir(base_path.get_base_dir());
+ current_action = p_id;
+ save_path->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_path_changed(const String &p_path) {
+ save_path_item->set_text(1, p_path);
+
+ if (FileAccess::exists(p_path)) {
+ save_path_item->set_text(2, "Warning: File exists");
+ save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ save_path_item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ save_path_item->set_text(2, "Will create new File");
+ save_path_item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+}
+
+void SceneImportSettings::_browse_save_callback(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+
+ String path = item->get_text(1);
+
+ item_save_path->set_current_file(path);
+ save_path_item = item;
+
+ item_save_path->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_dir_callback(const String &p_path) {
+ external_path_tree->clear();
+ TreeItem *root = external_path_tree->create_item();
+ save_path_items.clear();
+
+ switch (current_action) {
+ case ACTION_EXTRACT_MATERIALS: {
+ for (Map<String, MaterialData>::Element *E = material_map.front(); E; E = E->next()) {
+ MaterialData &md = material_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = md.material_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("StandardMaterial3D", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (md.has_import_id) {
+ if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
+ item->set_text(2, "Already External");
+ item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will create new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ } else {
+ item->set_text(2, "No import ID");
+ item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_icon(2, get_theme_icon("StatusError", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Extract Materials to Resource Files"));
+ external_paths->get_ok_button()->set_text(TTR("Extract"));
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ for (Map<String, MeshData>::Element *E = mesh_map.front(); E; E = E->next()) {
+ MeshData &md = mesh_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = md.mesh_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("Mesh", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (md.has_import_id) {
+ if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
+ item->set_text(2, "Already Saving");
+ item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will save to new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ } else {
+ item->set_text(2, "No import ID");
+ item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_icon(2, get_theme_icon("StatusError", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Set paths to save meshes as resource files on Reimport"));
+ external_paths->get_ok_button()->set_text(TTR("Set Paths"));
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ for (Map<String, AnimationData>::Element *E = animation_map.front(); E; E = E->next()) {
+ AnimationData &ad = animation_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = ad.scene_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("Animation", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
+ item->set_text(2, "Already Saving");
+ item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will save to new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Set paths to save animations as resource files on Reimport"));
+ external_paths->get_ok_button()->set_text(TTR("Set Paths"));
+
+ } break;
+ }
+
+ external_paths->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_dir_confirm() {
+ for (int i = 0; i < save_path_items.size(); i++) {
+ TreeItem *item = save_path_items[i];
+ if (!item->is_checked(0)) {
+ continue; //ignore
+ }
+ String path = item->get_text(1);
+ if (!path.is_resource_file()) {
+ continue;
+ }
+
+ String id = item->get_metadata(0);
+
+ switch (current_action) {
+ case ACTION_EXTRACT_MATERIALS: {
+ ERR_CONTINUE(!material_map.has(id));
+ MaterialData &md = material_map[id];
+
+ Error err = ResourceSaver::save(path, md.material);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Can't make material external to file, write error:") + "\n\t" + path);
+ continue;
+ }
+
+ md.settings["use_external/enabled"] = true;
+ md.settings["use_external/path"] = path;
+
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ ERR_CONTINUE(!mesh_map.has(id));
+ MeshData &md = mesh_map[id];
+
+ md.settings["save_to_file/enabled"] = true;
+ md.settings["save_to_file/path"] = path;
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ ERR_CONTINUE(!animation_map.has(id));
+ AnimationData &ad = animation_map[id];
+
+ ad.settings["save_to_file/enabled"] = true;
+ ad.settings["save_to_file/path"] = path;
+
+ } break;
+ }
+ }
+
+ if (current_action == ACTION_EXTRACT_MATERIALS) {
+ //as this happens right now, the scene needs to be saved and reimported.
+ _re_import();
+ open_settings(base_path);
+ } else {
+ scene_import_settings_data->notify_property_list_changed();
+ }
+}
+
+SceneImportSettings::SceneImportSettings() {
+ singleton = this;
+
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+ HBoxContainer *menu_hb = memnew(HBoxContainer);
+ main_vb->add_child(menu_hb);
+
+ action_menu = memnew(MenuButton);
+ action_menu->set_text(TTR("Actions..."));
+ menu_hb->add_child(action_menu);
+
+ action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
+ action_menu->get_popup()->add_separator();
+ action_menu->get_popup()->add_item(TTR("Set Animation Save Paths"), ACTION_CHOOSE_ANIMATION_SAVE_PATHS);
+ action_menu->get_popup()->add_item(TTR("Set Mesh Save Paths"), ACTION_CHOOSE_MESH_SAVE_PATHS);
+
+ action_menu->get_popup()->connect("id_pressed", callable_mp(this, &SceneImportSettings::_menu_callback));
+
+ tree_split = memnew(HSplitContainer);
+ main_vb->add_child(tree_split);
+ tree_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ data_mode = memnew(TabContainer);
+ tree_split->add_child(data_mode);
+ data_mode->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
+
+ property_split = memnew(HSplitContainer);
+ tree_split->add_child(property_split);
+ property_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ scene_tree = memnew(Tree);
+ scene_tree->set_name(TTR("Scene"));
+ data_mode->add_child(scene_tree);
+ scene_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_scene_tree_selected));
+
+ mesh_tree = memnew(Tree);
+ mesh_tree->set_name(TTR("Meshes"));
+ data_mode->add_child(mesh_tree);
+ mesh_tree->set_hide_root(true);
+ mesh_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_mesh_tree_selected));
+
+ material_tree = memnew(Tree);
+ material_tree->set_name(TTR("Materials"));
+ data_mode->add_child(material_tree);
+ material_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_material_tree_selected));
+
+ material_tree->set_hide_root(true);
+
+ SubViewportContainer *vp_container = memnew(SubViewportContainer);
+ vp_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_container->set_custom_minimum_size(Size2(10, 10));
+ vp_container->set_stretch(true);
+ vp_container->connect("gui_input", callable_mp(this, &SceneImportSettings::_viewport_input));
+ property_split->add_child(vp_container);
+
+ base_viewport = memnew(SubViewport);
+ vp_container->add_child(base_viewport);
+
+ base_viewport->set_use_own_world_3d(true);
+
+ camera = memnew(Camera3D);
+ base_viewport->add_child(camera);
+ camera->make_current();
+
+ light = memnew(DirectionalLight3D);
+ light->set_transform(Transform().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
+ base_viewport->add_child(light);
+ light->set_shadow(true);
+
+ {
+ Ref<StandardMaterial3D> selection_mat;
+ selection_mat.instance();
+ selection_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ selection_mat->set_albedo(Color(1, 0.8, 1.0));
+
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_LINES);
+
+ AABB base_aabb;
+ base_aabb.size = Vector3(1, 1, 1);
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ base_aabb.get_edge(i, a, b);
+
+ st->add_vertex(a);
+ st->add_vertex(a.lerp(b, 0.2));
+ st->add_vertex(b);
+ st->add_vertex(b.lerp(a, 0.2));
+ }
+
+ selection_mesh.instance();
+ st->commit(selection_mesh);
+ selection_mesh->surface_set_material(0, selection_mat);
+
+ node_selected = memnew(MeshInstance3D);
+ node_selected->set_mesh(selection_mesh);
+ base_viewport->add_child(node_selected);
+ node_selected->hide();
+ }
+
+ {
+ mesh_preview = memnew(MeshInstance3D);
+ base_viewport->add_child(mesh_preview);
+ mesh_preview->hide();
+
+ material_preview.instance();
+ }
+
+ inspector = memnew(EditorInspector);
+ inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
+
+ property_split->add_child(inspector);
+
+ scene_import_settings_data = memnew(SceneImportSettingsData);
+
+ get_ok_button()->set_text(TTR("Reimport"));
+ get_cancel_button()->set_text(TTR("Close"));
+
+ external_paths = memnew(ConfirmationDialog);
+ add_child(external_paths);
+ external_path_tree = memnew(Tree);
+ external_paths->add_child(external_path_tree);
+ external_path_tree->connect("button_pressed", callable_mp(this, &SceneImportSettings::_browse_save_callback));
+ external_paths->connect("confirmed", callable_mp(this, &SceneImportSettings::_save_dir_confirm));
+ external_path_tree->set_columns(3);
+ external_path_tree->set_column_titles_visible(true);
+ external_path_tree->set_column_expand(0, true);
+ external_path_tree->set_column_min_width(0, 100 * EDSCALE);
+ external_path_tree->set_column_title(0, TTR("Resource"));
+ external_path_tree->set_column_expand(1, true);
+ external_path_tree->set_column_min_width(1, 100 * EDSCALE);
+ external_path_tree->set_column_title(1, TTR("Path"));
+ external_path_tree->set_column_expand(2, false);
+ external_path_tree->set_column_min_width(2, 200 * EDSCALE);
+ external_path_tree->set_column_title(2, TTR("Status"));
+ save_path = memnew(EditorFileDialog);
+ save_path->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
+ HBoxContainer *extension_hb = memnew(HBoxContainer);
+ save_path->get_vbox()->add_child(extension_hb);
+ extension_hb->add_spacer();
+ extension_hb->add_child(memnew(Label(TTR("Save Extension: "))));
+ external_extension_type = memnew(OptionButton);
+ extension_hb->add_child(external_extension_type);
+ external_extension_type->add_item(TTR("Text: *.tres"));
+ external_extension_type->add_item(TTR("Binary: *.res"));
+ external_path_tree->set_hide_root(true);
+ add_child(save_path);
+
+ item_save_path = memnew(EditorFileDialog);
+ item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ item_save_path->add_filter("*.tres;Text Resource");
+ item_save_path->add_filter("*.res;Binary Resource");
+ add_child(item_save_path);
+ item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed));
+
+ save_path->connect("dir_selected", callable_mp(this, &SceneImportSettings::_save_dir_callback));
+}
+
+SceneImportSettings::~SceneImportSettings() {
+ memdelete(scene_import_settings_data);
+}
diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h
new file mode 100644
index 0000000000..ddcf4a6d5d
--- /dev/null
+++ b/editor/import/scene_import_settings.h
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* scene_import_settings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 SCENEIMPORTSETTINGS_H
+#define SCENEIMPORTSETTINGS_H
+
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_inspector.h"
+#include "editor/import/resource_importer_scene.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/subviewport_container.h"
+#include "scene/gui/tab_container.h"
+#include "scene/gui/tree.h"
+#include "scene/resources/primitive_meshes.h"
+
+class SceneImportSettingsData;
+
+class SceneImportSettings : public ConfirmationDialog {
+ GDCLASS(SceneImportSettings, ConfirmationDialog)
+
+ static SceneImportSettings *singleton;
+
+ enum Actions {
+ ACTION_EXTRACT_MATERIALS,
+ ACTION_CHOOSE_MESH_SAVE_PATHS,
+ ACTION_CHOOSE_ANIMATION_SAVE_PATHS,
+ };
+
+ Node *scene = nullptr;
+
+ HSplitContainer *tree_split;
+ HSplitContainer *property_split;
+ TabContainer *data_mode;
+ Tree *scene_tree;
+ Tree *mesh_tree;
+ Tree *material_tree;
+
+ EditorInspector *inspector;
+
+ SubViewport *base_viewport;
+
+ Camera3D *camera;
+ bool first_aabb = false;
+ AABB contents_aabb;
+
+ DirectionalLight3D *light;
+ Ref<ArrayMesh> selection_mesh;
+ MeshInstance3D *node_selected;
+
+ MeshInstance3D *mesh_preview;
+ Ref<SphereMesh> material_preview;
+
+ float cam_rot_x;
+ float cam_rot_y;
+ float cam_zoom;
+
+ void _update_scene();
+
+ struct MaterialData {
+ bool has_import_id;
+ Ref<Material> material;
+ TreeItem *scene_node;
+ TreeItem *mesh_node;
+ TreeItem *material_node;
+
+ float cam_rot_x = -Math_PI / 4;
+ float cam_rot_y = -Math_PI / 4;
+ float cam_zoom = 1;
+
+ Map<StringName, Variant> settings;
+ };
+ Map<String, MaterialData> material_map;
+
+ struct MeshData {
+ bool has_import_id;
+ Ref<Mesh> mesh;
+ TreeItem *scene_node;
+ TreeItem *mesh_node;
+
+ float cam_rot_x = -Math_PI / 4;
+ float cam_rot_y = -Math_PI / 4;
+ float cam_zoom = 1;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, MeshData> mesh_map;
+
+ struct AnimationData {
+ Ref<Animation> animation;
+ TreeItem *scene_node;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, AnimationData> animation_map;
+
+ struct NodeData {
+ Node *node;
+ TreeItem *scene_node;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, NodeData> node_map;
+
+ void _fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent);
+ void _fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent);
+ void _fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent);
+ void _fill_scene(Node *p_node, TreeItem *p_parent_item);
+
+ Set<Ref<Mesh>> mesh_set;
+ Set<Ref<Material>> material_set;
+
+ String selected_type;
+ String selected_id;
+
+ bool selecting = false;
+
+ void _update_camera();
+ void _select(Tree *p_from, String p_type, String p_id);
+ void _material_tree_selected();
+ void _mesh_tree_selected();
+ void _scene_tree_selected();
+
+ void _viewport_input(const Ref<InputEvent> &p_input);
+
+ Map<StringName, Variant> defaults;
+
+ SceneImportSettingsData *scene_import_settings_data;
+
+ void _re_import();
+
+ String base_path;
+
+ MenuButton *action_menu;
+
+ ConfirmationDialog *external_paths;
+ Tree *external_path_tree;
+ EditorFileDialog *save_path;
+ OptionButton *external_extension_type;
+
+ EditorFileDialog *item_save_path;
+
+ void _menu_callback(int p_id);
+ void _save_dir_callback(const String &p_path);
+
+ int current_action;
+
+ Vector<TreeItem *> save_path_items;
+
+ TreeItem *save_path_item = nullptr;
+ void _save_path_changed(const String &p_path);
+ void _browse_save_callback(Object *p_item, int p_column, int p_id);
+ void _save_dir_confirm();
+
+ Dictionary base_subresource_settings;
+
+ void _load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void open_settings(const String &p_path);
+ static SceneImportSettings *get_singleton();
+ SceneImportSettings();
+ ~SceneImportSettings();
+};
+
+#endif // SCENEIMPORTSETTINGS_H
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index 46eb4e4fdc..28fdd4ddbd 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -136,6 +136,11 @@ Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const
return surfaces[p_surface].material;
}
+void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_surface, surfaces.size());
+ surfaces.write[p_surface].material = p_material;
+}
+
void EditorSceneImporterMesh::generate_lods() {
if (!SurfaceTool::simplify_func) {
return;
@@ -219,11 +224,20 @@ bool EditorSceneImporterMesh::has_mesh() const {
return mesh.is_valid();
}
-Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
+Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<Mesh> &p_base) {
ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
if (mesh.is_null()) {
- mesh.instance();
+ if (p_base.is_valid()) {
+ mesh = p_base;
+ }
+ if (mesh.is_null()) {
+ mesh.instance();
+ }
+ mesh->set_name(get_name());
+ if (has_meta("import_id")) {
+ mesh->set_meta("import_id", get_meta("import_id"));
+ }
for (int i = 0; i < blend_shapes.size(); i++) {
mesh->add_blend_shape(blend_shapes[i]);
}
@@ -251,6 +265,8 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
}
}
+ mesh->set_lightmap_size_hint(lightmap_size_hint);
+
if (shadow_mesh.is_valid()) {
Ref<ArrayMesh> shadow = shadow_mesh->get_mesh();
mesh->set_shadow_mesh(shadow);
@@ -436,6 +452,338 @@ Dictionary EditorSceneImporterMesh::_get_data() const {
return data;
}
+Vector<Face3> EditorSceneImporterMesh::get_faces() const {
+ Vector<Face3> faces;
+ for (int i = 0; i < surfaces.size(); i++) {
+ if (surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ Vector<Vector3> vertices = surfaces[i].arrays[Mesh::ARRAY_VERTEX];
+ Vector<int> indices = surfaces[i].arrays[Mesh::ARRAY_INDEX];
+ if (indices.size()) {
+ for (int j = 0; j < indices.size(); j += 3) {
+ Face3 f;
+ f.vertex[0] = vertices[indices[j + 0]];
+ f.vertex[1] = vertices[indices[j + 1]];
+ f.vertex[2] = vertices[indices[j + 2]];
+ faces.push_back(f);
+ }
+ } else {
+ for (int j = 0; j < vertices.size(); j += 3) {
+ Face3 f;
+ f.vertex[0] = vertices[j + 0];
+ f.vertex[1] = vertices[j + 1];
+ f.vertex[2] = vertices[j + 2];
+ faces.push_back(f);
+ }
+ }
+ }
+ }
+
+ return faces;
+}
+
+Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose() const {
+ ERR_FAIL_COND_V(!Mesh::convex_composition_function, Vector<Ref<Shape3D>>());
+
+ const Vector<Face3> faces = get_faces();
+
+ Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces);
+
+ Vector<Ref<Shape3D>> ret;
+
+ for (int i = 0; i < decomposed.size(); i++) {
+ Set<Vector3> points;
+ for (int j = 0; j < decomposed[i].size(); j++) {
+ points.insert(decomposed[i][j].vertex[0]);
+ points.insert(decomposed[i][j].vertex[1]);
+ points.insert(decomposed[i][j].vertex[2]);
+ }
+
+ Vector<Vector3> convex_points;
+ convex_points.resize(points.size());
+ {
+ Vector3 *w = convex_points.ptrw();
+ int idx = 0;
+ for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
+ w[idx++] = E->get();
+ }
+ }
+
+ Ref<ConvexPolygonShape3D> shape;
+ shape.instance();
+ shape->set_points(convex_points);
+ ret.push_back(shape);
+ }
+
+ return ret;
+}
+
+Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
+ Vector<Face3> faces = get_faces();
+ if (faces.size() == 0) {
+ return Ref<Shape3D>();
+ }
+
+ Vector<Vector3> face_points;
+ face_points.resize(faces.size() * 3);
+
+ for (int i = 0; i < face_points.size(); i += 3) {
+ Face3 f = faces.get(i / 3);
+ face_points.set(i, f.vertex[0]);
+ face_points.set(i + 1, f.vertex[1]);
+ face_points.set(i + 2, f.vertex[2]);
+ }
+
+ Ref<ConcavePolygonShape3D> shape = memnew(ConcavePolygonShape3D);
+ shape->set_faces(face_points);
+ return shape;
+}
+
+Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
+ Vector<Face3> faces = get_faces();
+ if (faces.size() == 0) {
+ return Ref<NavigationMesh>();
+ }
+
+ Map<Vector3, int> unique_vertices;
+ LocalVector<int> face_indices;
+
+ for (int i = 0; i < faces.size(); i++) {
+ for (int j = 0; j < 3; j++) {
+ Vector3 v = faces[i].vertex[j];
+ int idx;
+ if (unique_vertices.has(v)) {
+ idx = unique_vertices[v];
+ } else {
+ idx = unique_vertices.size();
+ unique_vertices[v] = idx;
+ }
+ face_indices.push_back(idx);
+ }
+ }
+
+ Vector<Vector3> vertices;
+ vertices.resize(unique_vertices.size());
+ for (Map<Vector3, int>::Element *E = unique_vertices.front(); E; E = E->next()) {
+ vertices.write[E->get()] = E->key();
+ }
+
+ Ref<NavigationMesh> nm;
+ nm.instance();
+ nm->set_vertices(vertices);
+
+ Vector<int> v3;
+ v3.resize(3);
+ for (uint32_t i = 0; i < face_indices.size(); i += 3) {
+ v3.write[0] = face_indices[i + 0];
+ v3.write[1] = face_indices[i + 1];
+ v3.write[2] = face_indices[i + 2];
+ nm->add_polygon(v3);
+ }
+
+ return nm;
+}
+
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+
+struct EditorSceneImporterMeshLightmapSurface {
+ Ref<Material> material;
+ LocalVector<SurfaceTool::Vertex> vertices;
+ Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX;
+ uint32_t format = 0;
+ String name;
+};
+
+Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+ ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
+
+ Vector<float> vertices;
+ Vector<float> normals;
+ Vector<int> indices;
+ Vector<float> uv;
+ Vector<Pair<int, int>> uv_indices;
+
+ Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
+
+ // Keep only the scale
+ Transform transform = p_base_transform;
+ transform.origin = Vector3();
+ transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+
+ Basis normal_basis = transform.basis.inverse().transposed();
+
+ for (int i = 0; i < get_surface_count(); i++) {
+ EditorSceneImporterMeshLightmapSurface s;
+ s.primitive = get_surface_primitive_type(i);
+
+ ERR_FAIL_COND_V_MSG(s.primitive != Mesh::PRIMITIVE_TRIANGLES, ERR_UNAVAILABLE, "Only triangles are supported for lightmap unwrap.");
+ Array arrays = get_surface_arrays(i);
+ s.material = get_surface_material(i);
+ s.name = get_surface_name(i);
+
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
+
+ Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ int vc = rvertices.size();
+ const Vector3 *r = rvertices.ptr();
+
+ Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
+
+ ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
+
+ const Vector3 *rn = rnormals.ptr();
+
+ int vertex_ofs = vertices.size() / 3;
+
+ vertices.resize((vertex_ofs + vc) * 3);
+ normals.resize((vertex_ofs + vc) * 3);
+ uv_indices.resize(vertex_ofs + vc);
+
+ for (int j = 0; j < vc; j++) {
+ Vector3 v = transform.xform(r[j]);
+ Vector3 n = normal_basis.xform(rn[j]).normalized();
+
+ vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ }
+
+ Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ int ic = rindices.size();
+
+ if (ic == 0) {
+ for (int j = 0; j < vc / 3; j++) {
+ if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ continue;
+ }
+
+ indices.push_back(vertex_ofs + j * 3 + 0);
+ indices.push_back(vertex_ofs + j * 3 + 1);
+ indices.push_back(vertex_ofs + j * 3 + 2);
+ }
+
+ } else {
+ const int *ri = rindices.ptr();
+
+ for (int j = 0; j < ic / 3; j++) {
+ if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ continue;
+ }
+ indices.push_back(vertex_ofs + ri[j * 3 + 0]);
+ indices.push_back(vertex_ofs + ri[j * 3 + 1]);
+ indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+ }
+ }
+
+ lightmap_surfaces.push_back(s);
+ }
+
+ //unwrap
+
+ float *gen_uvs;
+ int *gen_vertices;
+ int *gen_indices;
+ int gen_vertex_count;
+ int gen_index_count;
+ int size_x;
+ int size_y;
+
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+
+ if (!ok) {
+ return ERR_CANT_CREATE;
+ }
+
+ //remove surfaces
+ clear();
+
+ //create surfacetools for each surface..
+ Vector<Ref<SurfaceTool>> surfaces_tools;
+
+ for (int i = 0; i < lightmap_surfaces.size(); i++) {
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_TRIANGLES);
+ st->set_material(lightmap_surfaces[i].material);
+ st->set_meta("name", lightmap_surfaces[i].name);
+ surfaces_tools.push_back(st); //stay there
+ }
+
+ print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+ //go through all indices
+ for (int i = 0; i < gen_index_count; i += 3) {
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+
+ ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
+
+ int surface = uv_indices[gen_vertices[gen_indices[i + 0]]].first;
+
+ for (int j = 0; j < 3; j++) {
+ SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
+
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
+ surfaces_tools.write[surface]->set_color(v.color);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
+ surfaces_tools.write[surface]->set_uv(v.uv);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
+ surfaces_tools.write[surface]->set_normal(v.normal);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
+ Plane t;
+ t.normal = v.tangent;
+ t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
+ surfaces_tools.write[surface]->set_tangent(t);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
+ surfaces_tools.write[surface]->set_bones(v.bones);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
+ surfaces_tools.write[surface]->set_weights(v.weights);
+ }
+
+ Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
+ surfaces_tools.write[surface]->set_uv2(uv2);
+
+ surfaces_tools.write[surface]->add_vertex(v.vertex);
+ }
+ }
+
+ //generate surfaces
+
+ for (int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools.write[i]->index();
+ Array arrays = surfaces_tools.write[i]->commit_to_arrays();
+ add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
+ }
+
+ set_lightmap_size_hint(Size2(size_x, size_y));
+
+ if (!r_used_cache) {
+ //free stuff
+ ::free(gen_vertices);
+ ::free(gen_indices);
+ ::free(gen_uvs);
+ }
+
+ return OK;
+}
+
+void EditorSceneImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
+ lightmap_size_hint = p_size;
+}
+
+Size2i EditorSceneImporterMesh::get_lightmap_size_hint() const {
+ return lightmap_size_hint;
+}
+
void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
@@ -462,5 +810,8 @@ void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
+ ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &EditorSceneImporterMesh::set_lightmap_size_hint);
+ ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &EditorSceneImporterMesh::get_lightmap_size_hint);
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
}
diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h
index 42507cbe8c..3326fab55d 100644
--- a/editor/import/scene_importer_mesh.h
+++ b/editor/import/scene_importer_mesh.h
@@ -32,7 +32,10 @@
#define EDITOR_SCENE_IMPORTER_MESH_H
#include "core/io/resource.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
#include "scene/resources/mesh.h"
+#include "scene/resources/navigation_mesh.h"
// The following classes are used by importers instead of ArrayMesh and MeshInstance3D
// so the data is not registered (hence, quality loss), importing happens faster and
// its easier to modify before saving
@@ -63,6 +66,8 @@ class EditorSceneImporterMesh : public Resource {
Ref<EditorSceneImporterMesh> shadow_mesh;
+ Size2i lightmap_size_hint;
+
protected:
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
@@ -89,13 +94,24 @@ public:
float get_surface_lod_size(int p_surface, int p_lod) const;
Ref<Material> get_surface_material(int p_surface) const;
+ void set_surface_material(int p_surface, const Ref<Material> &p_material);
+
void generate_lods();
void create_shadow_mesh();
Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
+ Vector<Face3> get_faces() const;
+ Vector<Ref<Shape3D>> convex_decompose() const;
+ Ref<Shape3D> create_trimesh_shape() const;
+ Ref<NavigationMesh> create_navigation_mesh();
+ Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size);
+
+ void set_lightmap_size_hint(const Size2i &p_size);
+ Size2i get_lightmap_size_hint() const;
+
bool has_mesh() const;
- Ref<ArrayMesh> get_mesh();
+ Ref<ArrayMesh> get_mesh(const Ref<Mesh> &p_base = Ref<Mesh>());
void clear();
};
#endif // EDITOR_SCENE_IMPORTER_MESH_H
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 97a04e6557..ddc363113c 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -98,11 +98,9 @@ void ImportDock::set_edit_path(const String &p_path) {
return;
}
- params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(config->get_value("remap", "importer"));
- if (params->importer.is_null()) {
- clear();
- return;
- }
+ String importer_name = config->get_value("remap", "importer");
+
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
params->paths.clear();
params->paths.push_back(p_path);
@@ -124,11 +122,18 @@ void ImportDock::set_edit_path(const String &p_path) {
for (List<Pair<String, String>>::Element *E = importer_names.front(); E; E = E->next()) {
import_as->add_item(E->get().first);
import_as->set_item_metadata(import_as->get_item_count() - 1, E->get().second);
- if (E->get().second == params->importer->get_importer_name()) {
+ if (E->get().second == importer_name) {
import_as->select(import_as->get_item_count() - 1);
}
}
+ import_as->add_separator();
+ import_as->add_item(TTR("Keep File (No Import)"));
+ import_as->set_item_metadata(import_as->get_item_count() - 1, "keep");
+ if (importer_name == "keep") {
+ import_as->select(import_as->get_item_count() - 1);
+ }
+
import->set_disabled(false);
import_as->set_disabled(false);
preset->set_disabled(false);
@@ -138,7 +143,10 @@ void ImportDock::set_edit_path(const String &p_path) {
void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
List<ResourceImporter::ImportOption> options;
- params->importer->get_import_options(&options);
+
+ if (params->importer.is_valid()) {
+ params->importer->get_import_options(&options);
+ }
params->properties.clear();
params->values.clear();
@@ -156,6 +164,14 @@ void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
params->update();
_update_preset_menu();
+
+ if (params->importer.is_valid() && params->paths.size() == 1 && params->importer->has_advanced_options()) {
+ advanced->show();
+ advanced_spacer->show();
+ } else {
+ advanced->hide();
+ advanced_spacer->hide();
+ }
}
void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
@@ -258,11 +274,26 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
preset->set_disabled(false);
imported->set_text(vformat(TTR("%d Files"), p_paths.size()));
+
+ if (params->paths.size() == 1 && params->importer->has_advanced_options()) {
+ advanced->show();
+ advanced_spacer->show();
+ } else {
+ advanced->hide();
+ advanced_spacer->hide();
+ }
}
void ImportDock::_update_preset_menu() {
preset->get_popup()->clear();
+ if (params->importer.is_null()) {
+ preset->get_popup()->add_item(TTR("Default"));
+ preset->hide();
+ return;
+ }
+ preset->show();
+
if (params->importer->get_preset_count() == 0) {
preset->get_popup()->add_item(TTR("Default"));
} else {
@@ -282,20 +313,25 @@ void ImportDock::_update_preset_menu() {
void ImportDock::_importer_selected(int i_idx) {
String name = import_as->get_selected_metadata();
- Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
- ERR_FAIL_COND(importer.is_null());
+ if (name == "keep") {
+ params->importer.unref();
+ _update_options(Ref<ConfigFile>());
+ } else {
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
+ ERR_FAIL_COND(importer.is_null());
- params->importer = importer;
+ params->importer = importer;
- Ref<ConfigFile> config;
- if (params->paths.size()) {
- config.instance();
- Error err = config->load(params->paths[0] + ".import");
- if (err != OK) {
- config.unref();
+ Ref<ConfigFile> config;
+ if (params->paths.size()) {
+ config.instance();
+ Error err = config->load(params->paths[0] + ".import");
+ if (err != OK) {
+ config.unref();
+ }
}
+ _update_options(config);
}
- _update_options(config);
}
void ImportDock::_preset_selected(int p_idx) {
@@ -391,6 +427,13 @@ static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path)
void ImportDock::_reimport_attempt() {
bool need_restart = false;
bool used_in_resources = false;
+
+ String importer_name;
+ if (params->importer.is_valid()) {
+ importer_name = params->importer->get_importer_name();
+ } else {
+ importer_name = "keep";
+ }
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
config.instance();
@@ -398,7 +441,7 @@ void ImportDock::_reimport_attempt() {
ERR_CONTINUE(err != OK);
String imported_with = config->get_value("remap", "importer");
- if (imported_with != params->importer->get_importer_name()) {
+ if (imported_with != importer_name) {
need_restart = true;
if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) {
used_in_resources = true;
@@ -422,6 +465,11 @@ void ImportDock::_reimport_and_restart() {
EditorNode::get_singleton()->restart_editor();
}
+void ImportDock::_advanced_options() {
+ if (params->paths.size() == 1 && params->importer.is_valid()) {
+ params->importer->show_advanced_options(params->paths[0]);
+ }
+}
void ImportDock::_reimport() {
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
@@ -429,38 +477,45 @@ void ImportDock::_reimport() {
Error err = config->load(params->paths[i] + ".import");
ERR_CONTINUE(err != OK);
- String importer_name = params->importer->get_importer_name();
+ if (params->importer.is_valid()) {
+ String importer_name = params->importer->get_importer_name();
+
+ if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) {
+ //update only what is edited (checkboxes) if the importer is the same
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
+ if (params->checked.has(E->get().name)) {
+ config->set_value("params", E->get().name, params->values[E->get().name]);
+ }
+ }
+ } else {
+ //override entirely
+ config->set_value("remap", "importer", importer_name);
+ if (config->has_section("params")) {
+ config->erase_section("params");
+ }
- if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) {
- //update only what is edited (checkboxes) if the importer is the same
- for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
- if (params->checked.has(E->get().name)) {
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
config->set_value("params", E->get().name, params->values[E->get().name]);
}
}
- } else {
- //override entirely
- config->set_value("remap", "importer", importer_name);
- if (config->has_section("params")) {
- config->erase_section("params");
- }
- for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
- config->set_value("params", E->get().name, params->values[E->get().name]);
+ //handle group file
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ ERR_CONTINUE(!importer.is_valid());
+ String group_file_property = importer->get_option_group_file();
+ if (group_file_property != String()) {
+ //can import from a group (as in, atlas)
+ ERR_CONTINUE(!params->values.has(group_file_property));
+ String group_file = params->values[group_file_property];
+ config->set_value("remap", "group_file", group_file);
+ } else {
+ config->set_value("remap", "group_file", Variant()); //clear group file if unused
}
- }
- //handle group file
- Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
- ERR_CONTINUE(!importer.is_valid());
- String group_file_property = importer->get_option_group_file();
- if (group_file_property != String()) {
- //can import from a group (as in, atlas)
- ERR_CONTINUE(!params->values.has(group_file_property));
- String group_file = params->values[group_file_property];
- config->set_value("remap", "group_file", group_file);
} else {
- config->set_value("remap", "group_file", Variant()); //clear group file if unused
+ //set to no import
+ config->clear();
+ config->set_value("remap", "importer", "keep");
}
config->save(params->paths[i] + ".import");
@@ -531,10 +586,27 @@ ImportDock::ImportDock() {
import->set_text(TTR("Reimport"));
import->set_disabled(true);
import->connect("pressed", callable_mp(this, &ImportDock::_reimport_attempt));
+ if (!DisplayServer::get_singleton()->get_swap_cancel_ok()) {
+ advanced_spacer = hb->add_spacer();
+ advanced = memnew(Button);
+ advanced->set_text(TTR("Advanced..."));
+ hb->add_child(advanced);
+ }
hb->add_spacer();
hb->add_child(import);
hb->add_spacer();
+ if (DisplayServer::get_singleton()->get_swap_cancel_ok()) {
+ advanced = memnew(Button);
+ advanced->set_text(TTR("Advanced..."));
+ hb->add_child(advanced);
+ advanced_spacer = hb->add_spacer();
+ }
+
+ advanced->hide();
+ advanced_spacer->hide();
+ advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options));
+
reimport_confirm = memnew(ConfirmationDialog);
reimport_confirm->get_ok_button()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
add_child(reimport_confirm);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index 6c5779ddce..2be48dd505 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -57,6 +57,9 @@ class ImportDock : public VBoxContainer {
Label *label_warning;
Button *import;
+ Control *advanced_spacer;
+ Button *advanced;
+
ImportDockParameters *params;
void _preset_selected(int p_idx);
@@ -69,6 +72,7 @@ class ImportDock : public VBoxContainer {
void _reimport_and_restart();
void _reimport();
+ void _advanced_options();
enum {
ITEM_SET_AS_DEFAULT = 100,
ITEM_LOAD_DEFAULT,
diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp
index 16eefb1ad3..64cf9a7bb7 100644
--- a/editor/node_3d_editor_gizmos.cpp
+++ b/editor/node_3d_editor_gizmos.cpp
@@ -2073,7 +2073,13 @@ void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh();
Vector<Vector3> points;
- soft_body->get_mesh()->generate_debug_mesh_indices(points);
+ for (int i = 0; i < soft_body->get_mesh()->get_surface_count(); i++) {
+ Array arrays = soft_body->get_mesh()->surface_get_arrays(i);
+ ERR_CONTINUE(arrays.is_empty());
+
+ const Vector<Vector3> &vertices = arrays[Mesh::ARRAY_VERTEX];
+ points.append_array(vertices);
+ }
Ref<Material> material = get_material("shape_material", p_gizmo);
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 2a0e7d0732..f496811e0a 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -86,7 +86,7 @@ void PluginConfigDialog::_on_confirmed() {
// Hard-coded GDScript template to keep usability until we use script templates.
Ref<Script> gdscript = memnew(GDScript);
gdscript->set_source_code(
- "tool\n"
+ "@tool\n"
"extends EditorPlugin\n"
"\n"
"\n"
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 876b67fa77..c90f87de56 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -585,11 +585,11 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
edited_point = PosVertex();
hover_point = Vertex();
selected_point = Vertex();
-
- canvas_item_editor->update_viewport();
} else {
_set_node(nullptr);
}
+
+ canvas_item_editor->update_viewport();
}
void AbstractPolygon2DEditor::_bind_methods() {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index e7e069e8b6..fdbbe5184b 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -139,7 +139,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
name->set_expand_to_text_length(true);
node->add_child(name);
node->set_slot(0, false, 0, Color(), true, 0, get_theme_color("font_color", "Label"));
- name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode));
+ name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED);
base = 1;
node->set_show_close_button(true);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 030ce4655d..b7484aa748 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -584,6 +584,24 @@ void EditorAssetLibrary::_notification(int p_what) {
filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ _update_repository_options();
+ } break;
+ }
+}
+
+void EditorAssetLibrary::_update_repository_options() {
+ Dictionary default_urls;
+ default_urls["godotengine.org"] = "https://godotengine.org/asset-library/api";
+ default_urls["localhost"] = "http://127.0.0.1/asset-library/api";
+ Dictionary available_urls = _EDITOR_DEF("asset_library/available_urls", default_urls, true);
+ repository->clear();
+ Array keys = available_urls.keys();
+ for (int i = 0; i < available_urls.size(); i++) {
+ String key = keys[i];
+ repository->add_item(key);
+ repository->set_item_metadata(i, available_urls[key]);
}
}
@@ -1373,18 +1391,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(memnew(Label(TTR("Site:") + " ")));
repository = memnew(OptionButton);
- {
- Dictionary default_urls;
- default_urls["godotengine.org"] = "https://godotengine.org/asset-library/api";
- default_urls["localhost"] = "http://127.0.0.1/asset-library/api";
- Dictionary available_urls = _EDITOR_DEF("asset_library/available_urls", default_urls, true);
- Array keys = available_urls.keys();
- for (int i = 0; i < available_urls.size(); i++) {
- String key = keys[i];
- repository->add_item(key);
- repository->set_item_metadata(i, available_urls[key]);
- }
- }
+ _update_repository_options();
repository->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_repository_changed));
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 0509145673..11eae9e041 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -176,6 +176,7 @@ class EditorAssetLibrary : public PanelContainer {
void _asset_open();
void _asset_file_selected(const String &p_file);
+ void _update_repository_options();
PanelContainer *library_scroll_bg;
ScrollContainer *library_scroll;
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 5963092860..3553450672 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -105,6 +105,8 @@ void AudioStreamEditor::_audio_changed() {
void AudioStreamEditor::_play() {
if (_player->is_playing()) {
+ // '_pausing' variable indicates that we want to pause the audio player, not stop it. See '_on_finished()'.
+ _pausing = true;
_player->stop();
_play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
set_process(false);
@@ -125,10 +127,13 @@ void AudioStreamEditor::_stop() {
void AudioStreamEditor::_on_finished() {
_play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
- if (_current == _player->get_stream()->get_length()) {
+ if (!_pausing) {
_current = 0;
_indicator->update();
+ } else {
+ _pausing = false;
}
+ set_process(false);
}
void AudioStreamEditor::_draw_indicator() {
@@ -194,8 +199,6 @@ void AudioStreamEditor::_bind_methods() {
AudioStreamEditor::AudioStreamEditor() {
set_custom_minimum_size(Size2(1, 100) * EDSCALE);
- _current = 0;
- _dragging = false;
_player = memnew(AudioStreamPlayer);
_player->connect("finished", callable_mp(this, &AudioStreamEditor::_on_finished));
diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h
index aa906a6a05..14e829d025 100644
--- a/editor/plugins/audio_stream_editor_plugin.h
+++ b/editor/plugins/audio_stream_editor_plugin.h
@@ -41,17 +41,18 @@ class AudioStreamEditor : public ColorRect {
GDCLASS(AudioStreamEditor, ColorRect);
Ref<AudioStream> stream;
- AudioStreamPlayer *_player;
- ColorRect *_preview;
- Control *_indicator;
- Label *_current_label;
- Label *_duration_label;
+ AudioStreamPlayer *_player = nullptr;
+ ColorRect *_preview = nullptr;
+ Control *_indicator = nullptr;
+ Label *_current_label = nullptr;
+ Label *_duration_label = nullptr;
- Button *_play_button;
- Button *_stop_button;
+ Button *_play_button = nullptr;
+ Button *_stop_button = nullptr;
- float _current;
- bool _dragging;
+ float _current = 0;
+ bool _dragging = false;
+ bool _pausing = false;
void _audio_changed();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index bac6f3cd79..23467c8377 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2622,6 +2622,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
if (tool != TOOL_RULER) {
+ ruler_tool_active = false;
return false;
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 9643881f96..449968eb7b 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1841,9 +1841,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ const int mod = _get_key_modifier(m);
if (nav_scheme == NAVIGATION_GODOT) {
- const int mod = _get_key_modifier(m);
-
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
@@ -1854,7 +1853,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} else if (nav_scheme == NAVIGATION_MAYA) {
- if (m->get_alt()) {
+ if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
}
}
@@ -5821,7 +5820,7 @@ void Node3DEditor::_init_grid() {
// Offsets division_level for bigger or smaller grids.
// Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias");
- // Default largest grid size is 100m, 10^2 (default value is 2).
+ // Default largest grid size is 8^2 when primary_grid_steps is 8 (64m apart, so primary grid lines are 512m apart).
int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max");
// Default smallest grid size is 1cm, 10^-2 (default value is -2).
int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min");
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 4949d2b9b7..4acacf3058 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -179,7 +179,7 @@ void Sprite2DEditor::_update_mesh_data() {
}
Rect2 rect;
- if (node->is_region()) {
+ if (node->is_region_enabled()) {
rect = node->get_region_rect();
} else {
rect.size = Size2(image->get_width(), image->get_height());
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 0547f99079..a6949c873e 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -219,7 +219,8 @@ void SpriteFramesEditor::_sheet_zoom_out() {
}
void SpriteFramesEditor::_sheet_zoom_reset() {
- sheet_zoom = 1.f;
+ // Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
+ sheet_zoom = MAX(1.0, EDSCALE);
Size2 texture_size = split_sheet_preview->get_texture()->get_size();
split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
}
@@ -732,7 +733,7 @@ void SpriteFramesEditor::_zoom_out() {
}
void SpriteFramesEditor::_zoom_reset() {
- thumbnail_zoom = 1.0f;
+ thumbnail_zoom = MAX(1.0, EDSCALE);
tree->set_fixed_column_width(thumbnail_default_size * 3 / 2);
tree->set_fixed_icon_size(Size2(thumbnail_default_size, thumbnail_default_size));
}
@@ -1229,13 +1230,14 @@ SpriteFramesEditor::SpriteFramesEditor() {
// Config scale.
scale_ratio = 1.2f;
- thumbnail_default_size = 96;
- thumbnail_zoom = 1.0f;
- max_thumbnail_zoom = 8.0f;
- min_thumbnail_zoom = 0.1f;
- sheet_zoom = 1.0f;
- max_sheet_zoom = 16.0f;
- min_sheet_zoom = 0.01f;
+ thumbnail_default_size = 96 * MAX(1.0, EDSCALE);
+ thumbnail_zoom = MAX(1.0, EDSCALE);
+ max_thumbnail_zoom = 8.0f * MAX(1.0, EDSCALE);
+ min_thumbnail_zoom = 0.1f * MAX(1.0, EDSCALE);
+ // Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
+ sheet_zoom = MAX(1.0, EDSCALE);
+ max_sheet_zoom = 16.0f * MAX(1.0, EDSCALE);
+ min_sheet_zoom = 0.01f * MAX(1.0, EDSCALE);
_zoom_reset();
}
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 63255e6547..4cbfe18594 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -897,7 +897,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
atlas_tex = Ref<AtlasTexture>(nullptr);
}
edit_draw->update();
- if ((node_sprite && !node_sprite->is_region()) || (node_sprite_3d && !node_sprite_3d->is_region())) {
+ if ((node_sprite && !node_sprite->is_region_enabled()) || (node_sprite_3d && !node_sprite_3d->is_region_enabled())) {
set_process(true);
}
if (!p_obj) {
@@ -1115,7 +1115,7 @@ void TextureRegionEditorPlugin::_editor_visiblity_changed() {
void TextureRegionEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
texture_region_button->show();
- bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region()) || (region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region());
+ bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region_enabled()) || (region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region_enabled());
if ((is_node_configured && !manually_hidden) || texture_region_button->is_pressed()) {
editor->make_bottom_panel_item_visible(region_editor);
}
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 74b01b3c36..59730a4fd3 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -966,9 +966,9 @@ void TileMapEditor::_update_copydata() {
tcd.flip_v = node->is_cell_y_flipped(j, i);
tcd.transpose = node->is_cell_transposed(j, i);
tcd.autotile_coord = node->get_cell_autotile_coord(j, i);
- }
- copydata.push_back(tcd);
+ copydata.push_back(tcd);
+ }
}
}
}
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index c628fe8367..b97ee10743 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -80,7 +80,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
Vector2 phys_offset;
Size2 s;
- if (mi->is_region()) {
+ if (mi->is_region_enabled()) {
s = mi->get_region_rect().size;
p_library->tile_set_region(id, mi->get_region_rect());
} else {
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 7d421bdf81..f4aa628b65 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -487,7 +487,7 @@ private:
if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
- ResourceSaver::save(dir.plus_file("icon.png"), msg->get_theme_icon("DefaultProjectIcon", "EditorIcons"));
+ ResourceSaver::save(dir.plus_file("icon.png"), create_unscaled_default_project_icon());
FileAccess *f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
if (!f) {
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 2d739202fb..e9de91f851 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -626,7 +626,7 @@ void SceneTreeEditor::_selected_changed() {
}
void SceneTreeEditor::_deselect_items() {
- // Clear currently elected items in scene tree dock.
+ // Clear currently selected items in scene tree dock.
if (editor_selection) {
editor_selection->clear();
emit_signal("node_changed");
@@ -1172,6 +1172,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
tree->set_anchor(SIDE_BOTTOM, ANCHOR_END);
tree->set_begin(Point2(0, p_label ? 18 : 0));
tree->set_end(Point2(0, 0));
+ tree->set_allow_reselect(true);
tree->add_theme_constant_override("button_margin", 0);
add_child(tree);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 6b505a6784..fd5157f04f 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -181,6 +181,7 @@ protected:
public:
void popup_scenetree_dialog();
SceneTreeEditor *get_scene_tree() { return tree; }
+ LineEdit *get_filter_line_edit() { return filter; }
SceneTreeDialog();
~SceneTreeDialog();
};
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index 47fd10411a..848574a1f1 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -17,7 +17,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-15 10:51+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: Любомир Василев <lyubomirv@gmx.com>\n"
"Language-Team: Bulgarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/bg/>\n"
@@ -26,7 +26,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2446,40 +2446,50 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "Не може да се зареди скриптът на добавка от: „%s“."
+msgstr "Не може да бъде намерено полето за скрипт за добавката: „%s“."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "Не може да се зареди скриптът на добавка от: „%s“."
+msgstr "Не може да се зареди добавката-скрипт от: „%s“."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Изглежда има грешка в кода. "
+"Моля, проверете синтаксиса."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Базовият тип не е "
+"„EditorPlugin“."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Скриптът не е в режим на "
+"„инструмент“."
#: editor/editor_node.cpp
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
+"Сцената „%s“ е била внесена автоматично и затова не може да се променя.\n"
+"Ако искате да правите промени в нея, може да създадете нова сцена-наследник."
#: editor/editor_node.cpp
msgid ""
"Error loading scene, it must be inside the project path. Use 'Import' to "
"open the scene, then save it inside the project path."
msgstr ""
+"Грешка при зареждането на сцената. Тя трябва да се намира в папката на "
+"проекта. Използвайте „Внасяне“, за да отворите сцената, и след това я "
+"запазете някъде в папката на проекта."
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
@@ -2495,6 +2505,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Няма определена главна сцена. Искате ли да изберете такава сега?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid ""
@@ -2502,6 +2515,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Избраната сцена „%s“ не съществува. Искате ли да изберете друга?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid ""
@@ -2509,6 +2525,10 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Избраната сцена „%s“ не е файл съдържащ сцена. Искате ли да изберете "
+"подходящ файл?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid "Save Layout"
@@ -2992,13 +3012,12 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"Следните файлове са по-нови на диска.\n"
-"Кое действие трябва да се предприеме?:"
+"Кое действие трябва да се предприеме?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3896,23 +3915,20 @@ msgid "Saving..."
msgstr "Запазване..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Режим на избиране"
+msgstr "Изберете метод на внасяне"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Внасяне"
+msgstr "Метод на внасяне:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Задаване на входен порт по подразбиране"
+msgstr "Връщане на стандартните настройки"
#: editor/import_dock.cpp
msgid "%d Files"
-msgstr "%d Файлове"
+msgstr "%d файла"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
diff --git a/editor/translations/da.po b/editor/translations/da.po
index bc00612eae..72b2bf0e81 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
"Last-Translator: snakatk <snaqii@live.dk>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/godot-engine/"
"godot/da/>\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1648,16 +1648,22 @@ msgid "Packing"
msgstr "Pakker"
#: editor/editor_export.cpp
+#, fuzzy
msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"Målplatform kræver 'ETC' teksturkomprimering for GLES2. Aktivér 'Import Etc' "
+"i Projektindstillingerne."
#: editor/editor_export.cpp
+#, fuzzy
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"Målplatform kræver 'ETC2' teksturkomprimering for GLES3. Aktivér 'Import Etc "
+"2' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
@@ -1690,15 +1696,14 @@ msgstr ""
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
-#, fuzzy
msgid "Custom debug template not found."
-msgstr "Skabelonfil ikke fundet:"
+msgstr "Brugerdefineret debug skabelonfil ikke fundet:"
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr ""
+msgstr "Brugerdefineret release skabelonfil ikke fundet."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
@@ -1743,13 +1748,12 @@ msgid "Import Dock"
msgstr "Importer"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Erase profile '%s'? (no undo)"
-msgstr "Erstat Alle"
+msgstr "Slet profil '%s'? (kan ikke fortrydes)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profil skal være et gyldigt filnavn og må ikke indeholde '.'"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1828,7 +1832,7 @@ msgstr "(Nuværende)"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "New"
-msgstr ""
+msgstr "Ny"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
diff --git a/editor/translations/de.po b/editor/translations/de.po
index bf3c01ae14..ffd8a8874e 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -71,8 +71,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-07 06:04+0000\n"
-"Last-Translator: El Captian <elcaptian@posteo.me>\n"
+"PO-Revision-Date: 2021-03-09 04:13+0000\n"
+"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -4148,19 +4148,16 @@ msgid "Saving..."
msgstr "Speichere..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Auswahlmodus"
+msgstr "Importer auswählen"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Import"
+msgstr "Importer:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Nutze Standard-sRGB"
+msgstr "Auf Standardwerte zurücksetzen"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10531,9 +10528,8 @@ msgid "Plugins"
msgstr "Erweiterungen"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Standard laden"
+msgstr "Standardwerte importieren"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12598,10 +12594,14 @@ msgstr "Ein leeres CollisionPolygon2D hat keinen Effekt auf Kollisionen."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Ungültiges Polygon. Mindestens drei Punkte werden im ‚Festkörper‘-Baumodus "
+"benötigt."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Ungültiges Polygon. Mindestens zwei Punkte werden im ‚Segment‘-Baumodus "
+"benötigt."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 85b79a7605..4f8441fbfc 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -63,7 +63,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
@@ -72,7 +72,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4145,19 +4145,16 @@ msgid "Saving..."
msgstr "Guardando..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Modo de Selección"
+msgstr "Seleccionar Importador"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importación"
+msgstr "Importador:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Usar sRGB predeterminado"
+msgstr "Restablecer Valores por Defecto"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10523,9 +10520,8 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Cargar Valores por Defecto"
+msgstr "Valores de Importación por Defecto"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12605,10 +12601,14 @@ msgstr "Un CollisionPolygon2D vacío no tiene ningún efecto en las colisiones."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Polígono inválido. Se necesitan al menos 3 puntos en modo de construcción "
+"'Solids'."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Polígono inválido. Se necesitan al menos 2 puntos en modo de construcción "
+"'Segments'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 5f9231e891..11e55b2dfa 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-09 04:13+0000\n"
"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.1\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4096,19 +4096,16 @@ msgid "Saving..."
msgstr "Guardando..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Modo Seleccionar"
+msgstr "Seleccionar Importador"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importar"
+msgstr "Importador:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Usar sRGB por Defecto"
+msgstr "Restablecer Valores Por Defecto"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10467,9 +10464,8 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Cargar Valores por Defecto"
+msgstr "Valores de Importacion Por Defecto"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12540,10 +12536,14 @@ msgstr "Un CollisionPolygon2D vacío no tiene efecto en la colisión."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Polígono inválido. Se necesitan al menos 3 puntos en modo de construcción "
+"\"Sólidos\"."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Polígono inválido. Se necesitan al menos 2 puntos en modo de construcción "
+"\"Segmentos\"."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 910212f856..1ac27a6fd6 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -19,12 +19,13 @@
# MSKF <walkingdeadstudio@outlook.com>, 2020.
# Ahmad Maftoun <CarCedo.Pro@gmail.com>, 2020.
# ItzMiad44909858f5774b6d <maidggg@gmail.com>, 2020.
+# YASAN <yasandev@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-08 10:26+0000\n"
-"Last-Translator: MSKF <walkingdeadstudio@outlook.com>\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
+"Last-Translator: YASAN <yasandev@gmail.com>\n"
"Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/"
"godot/fa/>\n"
"Language: fa\n"
@@ -32,16 +33,16 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.3.2\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "نوع ورودی برای ()convert نامعتبر است, ثوابت *_TYPE‌ بکار گیرید ."
+msgstr "نوع نامعتبر ورودی برای ()convert، ثوابت *_TYPE‌ را بکار گیرید."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "یک رشته (string) در اندازه 1 (کاراکتر) انتظار می رود."
+msgstr "یک رشته به‌طول 1 ( یک کاراکتر) مورد انتظار است."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -1040,11 +1041,10 @@ msgid "Owners Of:"
msgstr "مالکانِ:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "آیا پرونده‌های انتخاب شده از طرح حذف شوند؟ (نمی‌توان بازیابی کرد)"
+msgstr "آیا پرونده‌های انتخاب شده از طرح حذف شوند؟ (غیر قابل بازیابی)"
#: editor/dependency_editor.cpp
#, fuzzy
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 36e6c631be..4d690bd29d 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
@@ -24,7 +24,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4056,19 +4056,16 @@ msgid "Saving..."
msgstr "Tallennetaan..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Valintatila"
+msgstr "Valitse tuoja"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Tuonti"
+msgstr "Tuoja:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Lataa oletus"
+msgstr "Palauta oletusarvoihin"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10409,9 +10406,8 @@ msgid "Plugins"
msgstr "Liitännäiset"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Lataa oletus"
+msgstr "Lataa oletusarvot"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12466,10 +12462,14 @@ msgstr "Tyhjällä CollisionPolygon2D solmulla ei ole vaikutusta törmäyksessä
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Virheellinen polygoni. 'Solids' luontitilassa tarvitaan ainakin kolme "
+"pistettä."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Virheellinen polygoni. 'Segments' luontitilassa tarvitaan ainakin kaksi "
+"pistettä."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index 1d399091c3..67b524937c 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -50,7 +50,7 @@
# J. Lavoie <j.lavoie@net-c.ca>, 2020.
# Andrea Terenziani <andrea.terenziani.at@gmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
-# riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020.
+# riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020, 2021.
# Lorenzo Asolan <brixiumx@gmail.com>, 2020.
# Lorenzo Cerqua <lorenzocerqua@tutanota.com>, 2020, 2021.
# Federico Manzella <ferdiu.manzella@gmail.com>, 2020.
@@ -60,8 +60,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-07 06:04+0000\n"
-"Last-Translator: Riteo Siuga <lorenzocerqua@tutanota.com>\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
+"Last-Translator: riccardo boffelli <riccardo.boffelli.96@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -69,7 +69,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -253,7 +253,7 @@ msgstr "Traccia di chiamate di metodo"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr "Traccia curva di Bézier"
+msgstr "Traccia di curve di Bézier"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
@@ -273,11 +273,11 @@ msgstr "Durata dell'animazione (secondi)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
-msgstr "Aggiungi Traccia"
+msgstr "Aggiungi una traccia"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
-msgstr "Ciclicità Animazione"
+msgstr "Ciclicità animazione"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -286,11 +286,11 @@ msgstr "Funzioni:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
-msgstr "Clip Audio:"
+msgstr "Clip audio:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr "Clip Animazione:"
+msgstr "Clip animazione:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -302,15 +302,15 @@ msgstr "Attiva/Disattiva questa traccia."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr "Modalità Aggiornamento (come viene impostata questa proprietà)"
+msgstr "Modalità di aggiornamento (come viene impostata questa proprietà)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr "Modalità Interpolazione"
+msgstr "Modalità d'interpolazione"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr "Modalità Ciclo ad Anello (interpola la fine con l'inizio a ciclo)"
+msgstr "Modalità ciclo ad anello (interpola la fine con l'inizio del ciclo)"
#: editor/animation_track_editor.cpp
msgid "Remove this track."
@@ -322,7 +322,7 @@ msgstr "Tempo (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
-msgstr "Abilita/DisabilitaTraccia"
+msgstr "Abilita/Disabilita una traccia"
#: editor/animation_track_editor.cpp
msgid "Continuous"
@@ -334,7 +334,7 @@ msgstr "Discreta"
#: editor/animation_track_editor.cpp
msgid "Trigger"
-msgstr "Attivatore"
+msgstr "Attivazione"
#: editor/animation_track_editor.cpp
msgid "Capture"
@@ -355,32 +355,32 @@ msgstr "Cubica"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
-msgstr "Blocca Interpolazione Ciclo"
+msgstr "Blocca l'interpolazione d'un ciclo"
#: editor/animation_track_editor.cpp
msgid "Wrap Loop Interp"
-msgstr "Avvolgi Interpolazione Ciclo"
+msgstr "Continua l'interpolazione d'un ciclo"
#: editor/animation_track_editor.cpp
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key"
-msgstr "Inserisci Fotogramma Chiave"
+msgstr "Inserisci un fotogramma chiave"
#: editor/animation_track_editor.cpp
msgid "Duplicate Key(s)"
-msgstr "Duplica Fotogrammi Chiave Selezionati"
+msgstr "Duplica i fotogrammi chiave selezionati"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
-msgstr "Elimina Fotogrammi Chiave Selezionati"
+msgstr "Elimina i fotogrammi chiave selezionati"
#: editor/animation_track_editor.cpp
msgid "Change Animation Update Mode"
-msgstr "Cambia Modalità Aggiornamento Animazione"
+msgstr "Cambia la modalità d'aggiornamento di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Change Animation Interpolation Mode"
-msgstr "Cambia Modalità Interpolazione Animazione"
+msgstr "Cambia la modalità d'interpolazione di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
@@ -4145,9 +4145,8 @@ msgid "Importer:"
msgstr "Importare"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Usa sRGB Default"
+msgstr "Ripristinare le impostazioni predefinite"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10523,7 +10522,6 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
msgstr "Carica Predefiniti"
@@ -12596,10 +12594,14 @@ msgstr "Un CollisionPolygon2D vuoto non ha effetti sulla collisione."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Poligono non valido. Sono necessari almeno 3 punti nella modalità di "
+"costruzione 'Solidi'."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Poligono non valido. Sono necessari almeno 2 punti nella modalità di "
+"costruzione 'Segmenti'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index b898f397f4..693b726ebf 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -25,7 +25,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-08 15:33+0000\n"
+"PO-Revision-Date: 2021-03-12 09:17+0000\n"
"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
@@ -34,7 +34,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4051,19 +4051,16 @@ msgid "Saving..."
msgstr "저장 중..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "모드 선택"
+msgstr "임포터 선택"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "가져오기"
+msgstr "임포터:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "기본 sRGB 사용"
+msgstr "기본값으로 재설정"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10347,9 +10344,8 @@ msgid "Plugins"
msgstr "플러그인(Plugin)"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "기본값 불러오기"
+msgstr "기본값 가져오기"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12374,11 +12370,11 @@ msgstr "빈 CollisionPolygon2D는 충돌에 영향을 주지 않습니다."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "잘못된 폴리곤. 적어도 '솔리드' 빌드 모드에서 점 3개가 필요합니다."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
-msgstr ""
+msgstr "잘못된 폴리곤. 적어도 '세그먼트' 빌드 모드에서 점 2개가 필요합니다."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 173e86753f..d55fee8b72 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -51,7 +51,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -61,7 +61,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4092,19 +4092,16 @@ msgid "Saving..."
msgstr "Zapisywanie..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Tryb zaznaczenia"
+msgstr "Wybierz importer"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importuj"
+msgstr "Importer:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Użyj domyślnie sRGB"
+msgstr "Resetuj do domyślnych"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10448,9 +10445,8 @@ msgid "Plugins"
msgstr "Wtyczki"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Wczytaj domyślny"
+msgstr "Importuj domyślne"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12503,10 +12499,14 @@ msgstr "Pusty CollisionPolygon2D nie ma wpływu na kolizje."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Nieprawidłowy wielokąt. Co najmniej 3 punkty są potrzebne do trybu budowania "
+"\"Solids\"."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Nieprawidłowy wielokąt. Co najmniej 3 punkty są potrzebne do trybu budowania "
+"\"Segments\"."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index 28325d59bc..dd745d7c56 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-26 03:28+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2542,9 +2542,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "Incapaz de ativar plugin em: '%s' falha de análise ou configuração."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "Incapaz de localizar campo Script para plugin em: 'res://addons/%s'."
+msgstr "Incapaz de localizar campo script para plugin em: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3140,13 +3139,12 @@ msgid "Open & Run a Script"
msgstr "Abrir & Executar um Script"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
-"Os seguintes Ficheiros são mais recentes no disco.\n"
-"Que ação deve ser tomada?:"
+"Os seguintes ficheiros são mais recentes no disco.\n"
+"Que ação deve ser tomada?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -4077,19 +4075,16 @@ msgid "Saving..."
msgstr "A guardar..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Modo Seleção"
+msgstr "Selecionar Importador"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importar"
+msgstr "Importador:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Carregar Predefinição"
+msgstr "Restaurar Predefinições"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5057,9 +5052,8 @@ msgid "Got:"
msgstr "Obtido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "Verificação hash sha256 falhada"
+msgstr "Falhou a verificação hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -7359,9 +7353,8 @@ msgid "Yaw"
msgstr "Direção"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamanho: "
+msgstr "Tamanho"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -10043,9 +10036,8 @@ msgid "Projects"
msgstr "Projetos"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "A readquirir servidores, espere por favor..."
+msgstr "A carregar, espere por favor..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -10419,9 +10411,8 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Carregar Predefinição"
+msgstr "Importar Predefinições"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10672,14 +10663,12 @@ msgid "Instance Child Scene"
msgstr "Instanciar Cena Filha"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Não consigo operar em nós de uma cena externa!"
+msgstr "Não consigo colar o nó raiz na mesma cena."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
-msgstr "Colar Nós"
+msgstr "Colar Nó(s)"
#: editor/scene_tree_dock.cpp
msgid "Detach Script"
@@ -10808,9 +10797,8 @@ msgid "Attach Script"
msgstr "Anexar Script"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
-msgstr "Cortar Nós"
+msgstr "Cortar Nó(s)"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -12481,10 +12469,14 @@ msgstr "Um CollisionPolygon2D vazio não tem efeito na colisão."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Polígono inválido. São precisos pelo menos 3 pontos no modo de construção "
+"'Sólidos'."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Polígono inválido. São precisos pelo menos 2 pontos no modo de construção "
+"'Segmentos'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 4270648266..c2e8116938 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -20,7 +20,7 @@
# MalcomRF <malcomkbk@gmail.com>, 2017.
# Marcus Correia <marknokalt@live.com>, 2017-2018.
# Michael Alexsander Silva Dias <michaelalexsander@protonmail.com>, 2017-2018.
-# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019.
+# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021.
# Rodolfo R Gomes <rodolforg@gmail.com>, 2017-2018, 2019.
# Tiago Almeida <thyagoeap@gmail.com>, 2017.
# Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>, 2018.
@@ -116,8 +116,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2021-02-15 10:51+0000\n"
-"Last-Translator: Carlos Bonifacio <carlosboni.sa@gmail.com>\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
+"Last-Translator: Renato Rotenberg <renato.rotenberg@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -125,7 +125,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3236,13 +3236,12 @@ msgid "Open & Run a Script"
msgstr "Abrir e Rodar um Script"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"Os seguintes arquivos são mais recentes no disco.\n"
-"Que ação deve ser tomada?:"
+"Que ação deve ser tomada?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -7470,9 +7469,8 @@ msgid "Yaw"
msgstr "Guinada"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamanho: "
+msgstr "Tamanho"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -10158,9 +10156,8 @@ msgid "Projects"
msgstr "Projetos"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "Reconectando, por favor aguarde."
+msgstr "Carregando, por favor aguarde."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -10787,14 +10784,12 @@ msgid "Instance Child Scene"
msgstr "Instânciar Cena Filha"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Não é possível operar em nós de uma cena externa!"
+msgstr "Não é possível colar o nó raiz na mesma cena."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
-msgstr "Colar Nodes"
+msgstr "Colar Nó(s)"
#: editor/scene_tree_dock.cpp
msgid "Detach Script"
@@ -10923,9 +10918,8 @@ msgid "Attach Script"
msgstr "Adicionar Script"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
-msgstr "Recortar Nós"
+msgstr "Recortar Nó(s)"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -12598,10 +12592,14 @@ msgstr "Um nó CollisionPolygon2D vazio não é efetivo para colisão."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Polígono inválido. Pelo menos 3 pontos são necessários no modo de construção "
+"\"Sólidos\"."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Polígono inválido. Pelo menos 2 pontos são necessários no modo de construção "
+"\"Segmentos\"."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12816,9 +12814,8 @@ msgid "Finding meshes and lights"
msgstr "Encontrando malhas e luzes"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Analisando Geometria..."
+msgstr "Preparando geometria (%d/%d)"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing environment"
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index eec73e585a..5a443fd1e3 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -96,7 +96,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
@@ -106,7 +106,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4144,19 +4144,16 @@ msgid "Saving..."
msgstr "Сохранение..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Режим выделения"
+msgstr "Выберите импортёр"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Импорт"
+msgstr "Импортёр:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Использовать sRGB"
+msgstr "Сбросить настройки"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10492,9 +10489,8 @@ msgid "Plugins"
msgstr "Плагины"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Загрузить по умолчанию"
+msgstr "Шаблоны импорта"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12543,10 +12539,12 @@ msgstr "Пустой CollisionPolygon2D не влияет на столкнов
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Недопустимый полигон. В режиме «Solids» необходимо по крайней мере 3 точки."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Недопустимый полигон. В режиме «Segments» необходимо по крайней мере 2 точки."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index ecd57ee2cd..9a815d3f25 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -53,7 +53,7 @@
# Hazar <duurkak@yandex.com>, 2020.
# Mutlu ORAN <mutlu.oran66@gmail.com>, 2020.
# Yusuf Osman YILMAZ <wolfkan4219@gmail.com>, 2020.
-# furkan atalar <fatalar55@gmail.com>, 2020.
+# furkan atalar <fatalar55@gmail.com>, 2020, 2021.
# Suleyman Poyraz <zaryob.dev@gmail.com>, 2020.
# Çağlar KOPARIR <ckoparir@gmail.com>, 2021.
# Cem Eren Fukara <cefukara@hotmail.com>, 2021.
@@ -61,8 +61,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-03 15:50+0000\n"
-"Last-Translator: Oğuz Ersen <oguzersen@protonmail.com>\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
+"Last-Translator: furkan atalar <fatalar55@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -70,7 +70,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5.1-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -4112,19 +4112,16 @@ msgid "Saving..."
msgstr "Kaydediliyor..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Kip Seç"
+msgstr "İçe Aktarıcı'yı seçin"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
msgstr "İçe Aktar"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Önyüklü sRGB'yi Kullan"
+msgstr "Varsayılanlara dön"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5093,9 +5090,8 @@ msgid "Got:"
msgstr "Alınan:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "Başarısız sha256 hash sınaması"
+msgstr "SHA-256 hash kontrolü başarısız oldu"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -10456,7 +10452,7 @@ msgstr "Eklentiler"
#: editor/project_settings_editor.cpp
#, fuzzy
msgid "Import Defaults"
-msgstr "Varsayılanı Yükle"
+msgstr "Varsayılanları İçe Aktar"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10707,12 +10703,10 @@ msgid "Instance Child Scene"
msgstr "Çocuk Sahnesini Örnekle"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Yad bir sahnedeki düğümler üzerinde çalışamaz!"
+msgstr "Kök düğüm aynı sahneye yapıştırılamıyor."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
msgstr "Düğümleri Yapıştır"
@@ -10844,9 +10838,8 @@ msgid "Attach Script"
msgstr "Betik İliştir"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
-msgstr "Düğümleri Kes"
+msgstr "Düğümleri Kes(s)"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 4cdbe25d02..6a8af58119 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -12,7 +12,7 @@
# Kirill Omelchenko <kirill.omelchenko@gmail.com>, 2018.
# Александр <ol-vin@mail.ru>, 2018.
# Богдан Матвіїв <bomtvv@gmail.com>, 2019.
-# Tymofij Lytvynenko <till.svit@gmail.com>, 2020.
+# Tymofij Lytvynenko <till.svit@gmail.com>, 2020, 2021.
# Vladislav Glinsky <cl0ne@mithril.org.ua>, 2020.
# Микола Тимошенко <9081@ukr.net>, 2020.
# Miroslav <zinmirx@gmail.com>, 2020.
@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-22 21:30+0000\n"
-"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
+"Last-Translator: Tymofij Lytvynenko <till.svit@gmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1152,7 +1152,7 @@ msgstr "Ведучий розробник"
#. you do not have to keep it in your translation.
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr "Керівник проектів "
+msgstr "Керівник проєктів "
#: editor/editor_about.cpp
msgid "Developers"
@@ -4083,19 +4083,16 @@ msgid "Saving..."
msgstr "Збереження..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Режим виділення"
+msgstr "Виберіть засіб імпортування"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Імпорт"
+msgstr "Засіб імпортування:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Завантажити типовий"
+msgstr "Відновити типові параметри"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10069,7 +10066,7 @@ msgstr ""
#. TRANSLATORS: This refers to the application where users manage their Godot projects.
#: editor/project_manager.cpp
msgid "Project Manager"
-msgstr "Керівник проекту"
+msgstr "Керівник проєкту"
#: editor/project_manager.cpp
msgid "Projects"
@@ -10450,9 +10447,8 @@ msgid "Plugins"
msgstr "Плаґіни (додатки)"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Завантажити типовий"
+msgstr "Типові параметри імпортування"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12524,10 +12520,12 @@ msgstr "Порожній CollisionPolygon2D ніяк не вплине на зі
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Некоректний полігон. У режимі збирання «Solids» потрібно принаймні 3 точки."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Некоректний полігон. У режимі збирання «Segments» потрібні принаймні 2 точки."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index ac2d4a61f6..deca89e9ea 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -81,7 +81,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2021-03-08 15:33+0000\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -90,7 +90,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2696,7 +2696,7 @@ msgstr "专注模式"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr "进入/离开专注模式。"
+msgstr "切换专注模式。"
#: editor/editor_node.cpp
msgid "Add a new scene."
@@ -2936,7 +2936,7 @@ msgstr "截图将保存在编辑器数据或设置文件夹中。"
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "进入/离开全屏模式"
+msgstr "切换全屏模式"
#: editor/editor_node.cpp
msgid "Toggle System Console"
@@ -4045,19 +4045,16 @@ msgid "Saving..."
msgstr "保存中..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "选择模式"
+msgstr "选择导入器"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "导入"
+msgstr "导入器:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "使用默认sRGB"
+msgstr "重置为默认值"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5185,7 +5182,7 @@ msgstr "烘焙光照贴图"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
-msgstr "选择光照贴图烘焙文件:"
+msgstr "选择光照贴图烘焙文件:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5920,7 +5917,7 @@ msgstr "鼠标右键添加点"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
-msgstr "烘培 GI 探针"
+msgstr "烘焙 GI 探针"
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
@@ -6016,7 +6013,7 @@ msgstr "网格没有可用来创建轮廓的表面!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
-msgstr "Mesh 原始类型不是 PRIMITIVE_TRIANGLES!"
+msgstr "网格的原始类型不是 PRIMITIVE_TRIANGLES!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Could not create outline!"
@@ -6180,7 +6177,7 @@ msgstr "表面的源无效(路径无效)。"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Surface source is invalid (no geometry)."
-msgstr "表面的源无效(无几何)。"
+msgstr "表面的源无效(无几何体)。"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Surface source is invalid (no faces)."
@@ -6220,7 +6217,7 @@ msgstr "Y 轴"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Z-Axis"
-msgstr "Z轴"
+msgstr "Z 轴"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh Up Axis:"
@@ -6266,7 +6263,7 @@ msgstr "只可设为指向 ParticlesMaterial 处理材料"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Convert to CPUParticles2D"
-msgstr "转换为CPUParticles2D"
+msgstr "转换为 CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6295,7 +6292,7 @@ msgstr "“%s” 不包含面几何体。"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Create Emitter"
-msgstr "创建发射器 (Emitter)"
+msgstr "创建发射器"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Emission Points:"
@@ -10288,9 +10285,8 @@ msgid "Plugins"
msgstr "插件"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "加载默认"
+msgstr "默认导入设置"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -11509,7 +11505,7 @@ msgstr "内部异常堆栈追朔结束"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Bake NavMesh"
-msgstr "烘焙导航网"
+msgstr "烘焙导航网格"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Clear the navigation mesh."
@@ -12286,11 +12282,11 @@ msgstr "空的 CollisionPolygon2D 不起任何碰撞检测作用。"
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "多边形无效。“Solids”构建模式需要至少三个点。"
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
-msgstr ""
+msgstr "多边形无效。“Segments”构建模式需要至少两个点。"
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 5708d11522..62ef5a616c 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -29,7 +29,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
"Last-Translator: BinotaLIU <me@binota.org>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
@@ -38,7 +38,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3995,19 +3995,16 @@ msgid "Saving..."
msgstr "正在保存..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "選擇模式"
+msgstr "選擇匯入程式"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "匯入"
+msgstr "匯入程式:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "載入預設"
+msgstr "重設為預設"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -10239,9 +10236,8 @@ msgid "Plugins"
msgstr "外掛"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "載入預設"
+msgstr "匯入預設"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -12241,11 +12237,11 @@ msgstr "空白的 CollisionPolygon2D 不會產生任何碰撞效果。"
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "無效的多邊形。至少必須有三個點為「Solids」建構模式。"
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
-msgstr ""
+msgstr "無效的多邊形。至少必須有 2 個點為「Segments」建構模式。"
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/main/main.cpp b/main/main.cpp
index 9c8909f8fb..aa925c508c 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -529,7 +529,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
input_map = memnew(InputMap);
globals = memnew(ProjectSettings);
- register_core_settings(); //here globals is present
+ register_core_settings(); //here globals are present
translation_server = memnew(TranslationServer);
performance = memnew(Performance);
@@ -1517,7 +1517,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
input = memnew(Input);
- /* Iniitalize Display Server */
+ /* Initialize Display Server */
{
String rendering_driver; // temp broken
@@ -1547,12 +1547,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
display_server->screen_set_orientation(window_orientation);
}
- /* Initialize Pen Table Driver */
+ /* Initialize Pen Tablet Driver */
{
GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver", "");
- GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver.windows", "");
- ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pen_tablet/driver.windows", PropertyInfo(Variant::STRING, "input_devices/pen_tablet/driver.windows", PROPERTY_HINT_ENUM, "wintab,winink"));
+ GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver.Windows", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pen_tablet/driver.Windows", PropertyInfo(Variant::STRING, "input_devices/pen_tablet/driver.Windows", PROPERTY_HINT_ENUM, "wintab,winink"));
}
if (tablet_driver == "") { // specified in project.godot
@@ -1662,7 +1662,13 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
}
- Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
+#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
+ const Color boot_bg_color =
+ GLOBAL_DEF("application/boot_splash/bg_color",
+ (editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
+#else
+ const Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
+#endif
if (boot_logo.is_valid()) {
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
boot_logo_filter);
@@ -1796,7 +1802,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (!project_manager) {
// If not running the project manager, and now that the engine is
// able to load resources, load the global shader variables.
- // If running on editor, dont load the textures because the editor
+ // If running on editor, don't load the textures because the editor
// may want to import them first. Editor will reload those later.
rendering_server->global_variables_load_settings(!editor);
}
@@ -1804,7 +1810,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
_start_success = true;
locale = String();
- ClassDB::set_current_api(ClassDB::API_NONE); //no more api is registered at this point
+ ClassDB::set_current_api(ClassDB::API_NONE); //no more APIs are registered at this point
print_verbose("CORE API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_CORE)));
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
@@ -2606,7 +2612,7 @@ void Main::cleanup(bool p_force) {
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
RenderingServer::get_singleton()->sync();
- //clear global shader variables before scene and other graphics stuff is deinitialized.
+ //clear global shader variables before scene and other graphics stuff are deinitialized.
rendering_server->global_variables_clear();
#ifdef TOOLS_ENABLED
diff --git a/main/main_builders.py b/main/main_builders.py
index aa91201c3e..c880bfa3c4 100644
--- a/main/main_builders.py
+++ b/main/main_builders.py
@@ -17,6 +17,7 @@ def make_splash(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef BOOT_SPLASH_H\n")
g.write("#define BOOT_SPLASH_H\n")
+ # Use a neutral gray color to better fit various kinds of projects.
g.write("static const Color boot_splash_bg_color = Color(0.14, 0.14, 0.14);\n")
g.write("static const unsigned char boot_splash_png[] = {\n")
for i in range(len(buf)):
@@ -36,7 +37,9 @@ def make_splash_editor(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef BOOT_SPLASH_EDITOR_H\n")
g.write("#define BOOT_SPLASH_EDITOR_H\n")
- g.write("static const Color boot_splash_editor_bg_color = Color(0.14, 0.14, 0.14);\n")
+ # The editor splash background color is taken from the default editor theme's background color.
+ # This helps achieve a visually "smoother" transition between the splash screen and the editor.
+ g.write("static const Color boot_splash_editor_bg_color = Color(0.125, 0.145, 0.192);\n")
g.write("static const unsigned char boot_splash_editor_png[] = {\n")
for i in range(len(buf)):
g.write(str(buf[i]) + ",\n")
diff --git a/methods.py b/methods.py
index 9b29eadc16..725fb36caa 100644
--- a/methods.py
+++ b/methods.py
@@ -334,7 +334,7 @@ def use_windows_spawn_fix(self, platform=None):
# On Windows, due to the limited command line length, when creating a static library
# from a very high number of objects SCons will invoke "ar" once per object file;
# that makes object files with same names to be overwritten so the last wins and
- # the library looses symbols defined by overwritten objects.
+ # the library loses symbols defined by overwritten objects.
# By enabling quick append instead of the default mode (replacing), libraries will
# got built correctly regardless the invocation strategy.
# Furthermore, since SCons will rebuild the library from scratch when an object file
@@ -478,7 +478,7 @@ def detect_visual_c_compiler_version(tools_env):
# and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect
# the proper vc version that will be called
- # There is no flag to give to visual c compilers to set the architecture, ie scons bits argument (32,64,ARM etc)
+ # There is no flag to give to visual c compilers to set the architecture, i.e. scons bits argument (32,64,ARM etc)
# There are many different cl.exe files that are run, and each one compiles & links to a different architecture
# As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program()
# is to check the PATH variable and figure out which one will be called first. Code below does that and returns:
@@ -633,7 +633,7 @@ def generate_vs_project(env, num_jobs):
'call "' + batch_file + '" !plat!',
]
- # windows allows us to have spaces in paths, so we need
+ # Windows allows us to have spaces in paths, so we need
# to double quote off the directory. However, the path ends
# in a backslash, so we need to remove this, lest it escape the
# last double quote off, confusing MSBuild
diff --git a/misc/dist/html/manifest.json b/misc/dist/html/manifest.json
index 6e0053c23c..6fbed737c7 100644
--- a/misc/dist/html/manifest.json
+++ b/misc/dist/html/manifest.json
@@ -3,7 +3,7 @@
"short_name": "Godot",
"description": "Multi-platform 2D and 3D game engine with a feature-rich editor",
"lang": "en",
- "start_url": "/godot.tools.html",
+ "start_url": "./godot.tools.html",
"display": "standalone",
"orientation": "landscape",
"theme_color": "#478cbf",
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 1cbc576565..7c6e5fcb42 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -103,7 +103,7 @@ CLANG_FORMAT_VERSION="$(clang-format --version | cut -d' ' -f3)"
CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d'.' -f1)"
if [ "$CLANG_FORMAT_MAJOR" != "$RECOMMENDED_CLANG_FORMAT_MAJOR" ]; then
- echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $CLANG_FORMAT_MAJOR.x.x)."
+ echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x)."
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 26e9f5a044..93642f2d5c 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -433,12 +433,6 @@ void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) {
area->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::area_is_ray_pickable(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, false);
- return area->is_ray_pickable();
-}
-
RID BulletPhysicsServer3D::body_create(BodyMode p_mode, bool p_init_sleeping) {
RigidBodyBullet *body = bulletnew(RigidBodyBullet);
body->set_mode(p_mode);
@@ -461,7 +455,7 @@ void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) {
}
if (body->get_space() == space) {
- return; //pointles
+ return; //pointless
}
body->set_space(space);
@@ -617,11 +611,11 @@ uint32_t BulletPhysicsServer3D::body_get_collision_mask(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_user_flags(RID p_body, uint32_t p_flags) {
- // This function si not currently supported
+ // This function is not currently supported
}
uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const {
- // This function si not currently supported
+ // This function is not currently supported
return 0;
}
@@ -842,12 +836,6 @@ void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::body_is_ray_pickable(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, nullptr);
@@ -880,7 +868,7 @@ RID BulletPhysicsServer3D::soft_body_create(bool p_init_sleeping) {
CreateThenReturnRID(soft_body_owner, body);
}
-void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) {
+void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -898,7 +886,7 @@ void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) {
}
if (body->get_space() == space) {
- return; //pointles
+ return; //pointless
}
body->set_space(space);
@@ -922,6 +910,13 @@ void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
body->set_soft_mesh(p_mesh);
}
+AABB BulletPhysicsServer::soft_body_get_bounds(RID p_body) const {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, AABB());
+
+ return body->get_bounds();
+}
+
void BulletPhysicsServer3D::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -1002,34 +997,19 @@ void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform
body->set_soft_transform(p_transform);
}
-Vector3 BulletPhysicsServer3D::soft_body_get_vertex_position(RID p_body, int vertex_index) const {
- const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- Vector3 pos;
- ERR_FAIL_COND_V(!body, pos);
-
- body->get_node_position(vertex_index, pos);
- return pos;
-}
-
void BulletPhysicsServer3D::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::soft_body_is_ray_pickable(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
void BulletPhysicsServer3D::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_simulation_precision(p_simulation_precision);
}
-int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) {
+int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_simulation_precision();
@@ -1041,13 +1021,13 @@ void BulletPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_
body->set_total_mass(p_total_mass);
}
-real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_total_mass();
}
-void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
+void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_linear_stiffness(p_stiffness);
@@ -1059,61 +1039,25 @@ real_t BulletPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) {
return body->get_linear_stiffness();
}
-void BulletPhysicsServer3D::soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_angular_stiffness(p_stiffness);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_angular_stiffness(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_angular_stiffness();
-}
-
-void BulletPhysicsServer3D::soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_volume_stiffness(p_stiffness);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_volume_stiffness(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_volume_stiffness();
-}
-
void BulletPhysicsServer3D::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_pressure_coefficient(p_pressure_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pressure_coefficient();
}
-void BulletPhysicsServer3D::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- return body->set_pose_matching_coefficient(p_pose_matching_coefficient);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_pose_matching_coefficient(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_pose_matching_coefficient();
-}
-
void BulletPhysicsServer3D::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_damping_coefficient(p_damping_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_damping_coefficient();
@@ -1125,7 +1069,7 @@ void BulletPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_
body->set_drag_coefficient(p_drag_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_drag_coefficient();
@@ -1137,7 +1081,7 @@ void BulletPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index,
body->set_node_position(p_point_index, p_global_position);
}
-Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) {
+Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.));
Vector3 pos;
@@ -1145,14 +1089,6 @@ Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, i
return pos;
}
-Vector3 BulletPhysicsServer3D::soft_body_get_point_offset(RID p_body, int p_point_index) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector3());
- Vector3 res;
- body->get_node_offset(p_point_index, res);
- return res;
-}
-
void BulletPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -1165,7 +1101,7 @@ void BulletPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, b
body->set_node_mass(p_point_index, p_pin ? 0 : 1);
}
-bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) {
+bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_node_mass(p_point_index);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 97b719ae8e..856ff74963 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -163,7 +163,6 @@ public:
virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
- virtual bool area_is_ray_pickable(RID p_area) const override;
/* RIGID BODY API */
@@ -250,7 +249,6 @@ public:
virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_is_ray_pickable(RID p_body) const override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
@@ -262,13 +260,15 @@ public:
virtual RID soft_body_create(bool p_init_sleeping = false) override;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override;
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override;
virtual void soft_body_set_space(RID p_body, RID p_space) override;
virtual RID soft_body_get_space(RID p_body) const override;
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
+ virtual AABB soft_body_get_bounds(RID p_body) const override;
+
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override;
virtual uint32_t soft_body_get_collision_layer(RID p_body) const override;
@@ -284,46 +284,33 @@ public:
/// Special function. This function has bad performance
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool soft_body_is_ray_pickable(RID p_body) const override;
virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override;
- virtual int soft_body_get_simulation_precision(RID p_body) override;
+ virtual int soft_body_get_simulation_precision(RID p_body) const override;
virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override;
- virtual real_t soft_body_get_total_mass(RID p_body) override;
+ virtual real_t soft_body_get_total_mass(RID p_body) const override;
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_linear_stiffness(RID p_body) override;
-
- virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_angular_stiffness(RID p_body) override;
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_volume_stiffness(RID p_body) override;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const override;
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override;
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) override;
-
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override;
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override;
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override;
- virtual real_t soft_body_get_damping_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const override;
virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override;
- virtual real_t soft_body_get_drag_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const override;
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override;
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) override;
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override;
virtual void soft_body_remove_all_pinned_points(RID p_body) override;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override;
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) override;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override;
/* JOINT API */
diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp
index 7b21e4e4b2..19d4816372 100644
--- a/modules/bullet/bullet_types_converter.cpp
+++ b/modules/bullet/bullet_types_converter.cpp
@@ -116,7 +116,7 @@ void UNSCALE_BT_BASIS(btTransform &scaledBasis) {
}
} else { // Column 1 scale not fuzzy zero.
if (column2.fuzzyZero()) {
- // Create two vectors othogonal to column 1.
+ // Create two vectors orthogonal to column 1.
// Ensure that a default basis is created if column 1 = <0, 1, 0>
column0 = btVector3(column1[1], -column1[0], 0);
column2 = column0.cross(column1);
diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp
index 5d1e4d34d8..423166c408 100644
--- a/modules/bullet/godot_collision_dispatcher.cpp
+++ b/modules/bullet/godot_collision_dispatcher.cpp
@@ -43,7 +43,7 @@ GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *col
bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, const btCollisionObject *body1) {
if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
- // Avoide area narrow phase
+ // Avoid area narrow phase
return false;
}
return btCollisionDispatcher::needsCollision(body0, body1);
@@ -51,7 +51,7 @@ bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, co
bool GodotCollisionDispatcher::needsResponse(const btCollisionObject *body0, const btCollisionObject *body1) {
if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
- // Avoide area narrow phase
+ // Avoid area narrow phase
return false;
}
return btCollisionDispatcher::needsResponse(body0, body1);
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 15d625afeb..e92b6c189c 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -113,7 +113,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo
PhysicsDirectSpaceState3D::ShapeResult &result = m_results[count];
- result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
+ result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is an odd name but contains the compound shape ID
result.rid = gObj->get_self();
result.collider_id = gObj->get_instance_id();
result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id);
@@ -176,7 +176,7 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0)
btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
if (convexResult.m_localShapeInfo) {
- m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
+ m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is an odd name but contains the compound shape ID
} else {
m_shapeId = 0;
}
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index a5093afe9d..433bff8c38 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -515,7 +515,7 @@ real_t RigidBodyBullet::get_param(PhysicsServer3D::BodyParameter p_param) const
}
void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) {
- // This is necessary to block force_integration untile next move
+ // This is necessary to block force_integration until next move
can_integrate_forces = false;
destroy_kinematic_utilities();
// The mode change is relevant to its mass
@@ -725,7 +725,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
// 1 meter in one simulation frame
btBody->setCcdMotionThreshold(1e-7);
- /// Calculate using the rule writte below the CCD swept sphere radius
+ /// Calculate using the rule write below the CCD swept sphere radius
/// CCD works on an embedded sphere of radius, make sure this radius
/// is embedded inside the convex objects, preferably smaller:
/// for an object of dimensions 1 meter, try 0.2
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 82876ab77c..471b154813 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -375,11 +375,17 @@ ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
}
void ConcavePolygonShapeBullet::set_data(const Variant &p_data) {
- setup(p_data);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("faces"));
+
+ setup(d["faces"]);
}
Variant ConcavePolygonShapeBullet::get_data() const {
- return faces;
+ Dictionary d;
+ d["faces"] = faces;
+
+ return d;
}
PhysicsServer3D::ShapeType ConcavePolygonShapeBullet::get_type() const {
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 91a1934e07..2c8727baf2 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -65,7 +65,7 @@ void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {}
void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {}
-void SoftBodyBullet::update_rendering_server(SoftBodyRenderingServerHandler *p_rendering_server_handler) {
+void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) {
if (!bt_soft_body) {
return;
}
@@ -141,6 +141,24 @@ void SoftBodyBullet::set_soft_transform(const Transform &p_transform) {
move_all_nodes(p_transform);
}
+AABB SoftBodyBullet::get_bounds() const {
+ if (!bt_soft_body) {
+ return AABB();
+ }
+
+ btVector3 aabb_min;
+ btVector3 aabb_max;
+ bt_soft_body->getAabb(aabb_min, aabb_max);
+
+ btVector3 size(aabb_max - aabb_min);
+
+ AABB aabb;
+ B_TO_G(aabb_min, aabb.position);
+ B_TO_G(size, aabb.size);
+
+ return aabb;
+}
+
void SoftBodyBullet::move_all_nodes(const Transform &p_transform) {
if (!bt_soft_body) {
return;
@@ -169,25 +187,6 @@ void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) co
}
}
-void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const {
- if (soft_mesh.is_null()) {
- return;
- }
-
- Array arrays = soft_mesh->surface_get_arrays(0);
- Vector<Vector3> vertices(arrays[RS::ARRAY_VERTEX]);
-
- if (0 <= p_node_index && vertices.size() > p_node_index) {
- r_offset = vertices[p_node_index];
- }
-}
-
-void SoftBodyBullet::get_node_offset(int p_node_index, btVector3 &r_offset) const {
- Vector3 off;
- get_node_offset(p_node_index, off);
- G_TO_B(off, r_offset);
-}
-
void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) {
if (0 >= p_mass) {
pin_node(node_index);
@@ -259,20 +258,6 @@ void SoftBodyBullet::set_linear_stiffness(real_t p_val) {
}
}
-void SoftBodyBullet::set_angular_stiffness(real_t p_val) {
- angular_stiffness = p_val;
- if (bt_soft_body) {
- mat0->m_kAST = angular_stiffness;
- }
-}
-
-void SoftBodyBullet::set_volume_stiffness(real_t p_val) {
- volume_stiffness = p_val;
- if (bt_soft_body) {
- mat0->m_kVST = volume_stiffness;
- }
-}
-
void SoftBodyBullet::set_simulation_precision(int p_val) {
simulation_precision = p_val;
if (bt_soft_body) {
@@ -290,13 +275,6 @@ void SoftBodyBullet::set_pressure_coefficient(real_t p_val) {
}
}
-void SoftBodyBullet::set_pose_matching_coefficient(real_t p_val) {
- pose_matching_coefficient = p_val;
- if (bt_soft_body) {
- bt_soft_body->m_cfg.kMT = pose_matching_coefficient;
- }
-}
-
void SoftBodyBullet::set_damping_coefficient(real_t p_val) {
damping_coefficient = p_val;
if (bt_soft_body) {
@@ -336,7 +314,7 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector
Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]);
int vertex_id;
if (e) {
- // Already rxisting
+ // Already existing
vertex_id = e->value();
} else {
// Create new one
@@ -409,8 +387,6 @@ void SoftBodyBullet::setup_soft_body() {
bt_soft_body->generateBendingConstraints(2, mat0);
mat0->m_kLST = linear_stiffness;
- mat0->m_kAST = angular_stiffness;
- mat0->m_kVST = volume_stiffness;
// Clusters allow to have Soft vs Soft collision but doesn't work well right now
@@ -430,7 +406,6 @@ void SoftBodyBullet::setup_soft_body() {
bt_soft_body->m_cfg.kDP = damping_coefficient;
bt_soft_body->m_cfg.kDG = drag_coefficient;
bt_soft_body->m_cfg.kPR = pressure_coefficient;
- bt_soft_body->m_cfg.kMT = pose_matching_coefficient;
bt_soft_body->setTotalMass(total_mass);
btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body);
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index 23f6fba9a6..87023b2517 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -55,6 +55,8 @@
@author AndreaCatania
*/
+class RenderingServerHandler;
+
class SoftBodyBullet : public CollisionObjectBullet {
private:
btSoftBody *bt_soft_body = nullptr;
@@ -67,10 +69,7 @@ private:
int simulation_precision = 5;
real_t total_mass = 1.;
real_t linear_stiffness = 0.5; // [0,1]
- real_t angular_stiffness = 0.5; // [0,1]
- real_t volume_stiffness = 0.5; // [0,1]
real_t pressure_coefficient = 0.; // [-inf,+inf]
- real_t pose_matching_coefficient = 0.; // [0,1]
real_t damping_coefficient = 0.01; // [0,1]
real_t drag_coefficient = 0.; // [0,1]
Vector<int> pinned_nodes;
@@ -99,7 +98,7 @@ public:
_FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; }
- void update_rendering_server(class SoftBodyRenderingServerHandler *p_rendering_server_handler);
+ void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
void set_soft_mesh(const Ref<Mesh> &p_mesh);
void destroy_soft_body();
@@ -107,14 +106,12 @@ public:
// Special function. This function has bad performance
void set_soft_transform(const Transform &p_transform);
+ AABB get_bounds() const;
+
void move_all_nodes(const Transform &p_transform);
void set_node_position(int node_index, const Vector3 &p_global_position);
void set_node_position(int node_index, const btVector3 &p_global_position);
void get_node_position(int node_index, Vector3 &r_position) const;
- // Heavy function, Please cache this info
- void get_node_offset(int node_index, Vector3 &r_offset) const;
- // Heavy function, Please cache this info
- void get_node_offset(int node_index, btVector3 &r_offset) const;
void set_node_mass(int node_index, btScalar p_mass);
btScalar get_node_mass(int node_index) const;
@@ -129,21 +126,12 @@ public:
void set_linear_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
- void set_angular_stiffness(real_t p_val);
- _FORCE_INLINE_ real_t get_angular_stiffness() const { return angular_stiffness; }
-
- void set_volume_stiffness(real_t p_val);
- _FORCE_INLINE_ real_t get_volume_stiffness() const { return volume_stiffness; }
-
void set_simulation_precision(int p_val);
_FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; }
void set_pressure_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
- void set_pose_matching_coefficient(real_t p_val);
- _FORCE_INLINE_ real_t get_pose_matching_coefficient() const { return pose_matching_coefficient; }
-
void set_damping_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 7d337bc4d0..ceae3be8bc 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -81,7 +81,7 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape
btResult.m_collisionFilterMask = p_collision_mask;
space->dynamicsWorld->contactTest(&collision_object_point, btResult);
- // The results is already populated by GodotAllConvexResultCallback
+ // The results are already populated by GodotAllConvexResultCallback
return btResult.m_count;
}
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index f0a2f17ba9..8b46447f04 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -970,7 +970,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
continue;
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
face_points[face_edge_idx],
@@ -1076,7 +1076,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
break;
}
- // If opposite point is on the segemnt, add its index to segment indices too.
+ // If opposite point is on the segment, add its index to segment indices too.
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points);
if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) {
_add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx);
@@ -1137,7 +1137,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
}
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
bool on_edge = false;
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
@@ -1400,7 +1400,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
@@ -1421,7 +1421,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 40ba457e43..b97ee6ce4c 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -1160,7 +1160,7 @@ CSGBrush *CSGBox3D::_build_brush() {
materialsw[face] = material;
face++;
- //face 1
+ //face 2
facesw[face * 3 + 0] = face_points[2] * vertex_mul;
facesw[face * 3 + 1] = face_points[3] * vertex_mul;
facesw[face * 3 + 2] = face_points[0] * vertex_mul;
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 276f13e553..25b87145b6 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -248,7 +248,7 @@ void NetworkedMultiplayerENet::poll() {
int *new_id = memnew(int);
*new_id = event.data;
- if (*new_id == 0) { // Data zero is sent by server (enet won't let you configure this). Server is always 1.
+ if (*new_id == 0) { // Data zero is sent by server (ENet won't let you configure this). Server is always 1.
*new_id = 1;
}
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 883651943e..b088dd8640 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -417,6 +417,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
int bind_id = 0;
for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) {
+ ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + ".");
Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()];
skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id);
bind_id++;
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index 6576147b2b..e18ebe3930 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -628,7 +628,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
mesh_data_precached->mesh_node = fbx_node;
// mesh node, mesh id
- mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, (p_flags & IMPORT_USE_COMPRESSION) != 0);
+ mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, 0);
if (!state.MeshNodes.has(mesh_id)) {
state.MeshNodes.insert(mesh_id, fbx_node);
}
@@ -1132,7 +1132,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
max_duration = animation_track_time;
}
- rot_values.push_back(final_rotation);
+ rot_values.push_back(final_rotation.normalized());
rot_times.push_back(animation_track_time);
}
diff --git a/modules/gdnative/gdnative/aabb.cpp b/modules/gdnative/gdnative/aabb.cpp
index 5d3f224adc..c42b874b4b 100644
--- a/modules/gdnative/gdnative/aabb.cpp
+++ b/modules/gdnative/gdnative/aabb.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_aabb_new(godot_aabb *p_self) {
memnew_placement(p_self, AABB);
}
+void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src) {
+ memnew_placement(r_dest, AABB(*(AABB *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index e68b60c5e6..76e131dc06 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_array_new(godot_array *p_self) {
memnew_placement(p_self, Array);
}
+void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src) {
+ memnew_placement(r_dest, Array(*(Array *)p_src));
+}
+
void GDAPI godot_array_destroy(godot_array *p_self) {
((Array *)p_self)->~Array();
}
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index df3e1255ac..4641f0bacc 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_basis_new(godot_basis *p_self) {
memnew_placement(p_self, Basis);
}
+void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src) {
+ memnew_placement(r_dest, Basis(*(Basis *)p_src));
+}
+
godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index) {
Basis *self = (Basis *)p_self;
return (godot_vector3 *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative/callable.cpp b/modules/gdnative/gdnative/callable.cpp
index 7c62b5928f..85274e5e22 100644
--- a/modules/gdnative/gdnative/callable.cpp
+++ b/modules/gdnative/gdnative/callable.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_callable_new(godot_callable *p_self) {
memnew_placement(p_self, Callable);
}
+void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src) {
+ memnew_placement(r_dest, Callable(*(Callable *)p_src));
+}
+
void GDAPI godot_callable_destroy(godot_callable *p_self) {
Callable *self = (Callable *)p_self;
self->~Callable();
diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp
index 12a800d333..502f89c027 100644
--- a/modules/gdnative/gdnative/color.cpp
+++ b/modules/gdnative/gdnative/color.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_color_new(godot_color *p_self) {
memnew_placement(p_self, Color);
}
+void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src) {
+ memnew_placement(r_dest, Color(*(Color *)p_src));
+}
+
float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index) {
Color *self = (Color *)p_self;
return (float *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp
index 9fa4a27a83..2bfad6e695 100644
--- a/modules/gdnative/gdnative/dictionary.cpp
+++ b/modules/gdnative/gdnative/dictionary.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_dictionary_new(godot_dictionary *p_self) {
memnew_placement(p_self, Dictionary);
}
+void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src) {
+ memnew_placement(r_dest, Dictionary(*(Dictionary *)p_src));
+}
+
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) {
Dictionary *self = (Dictionary *)p_self;
self->~Dictionary();
diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp
index 02c2f9b22b..57d67b9abb 100644
--- a/modules/gdnative/gdnative/node_path.cpp
+++ b/modules/gdnative/gdnative/node_path.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_node_path_new(godot_node_path *p_self) {
memnew_placement(p_self, NodePath);
}
+void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src) {
+ memnew_placement(r_dest, NodePath(*(NodePath *)p_src));
+}
+
void GDAPI godot_node_path_destroy(godot_node_path *p_self) {
NodePath *self = (NodePath *)p_self;
self->~NodePath();
diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp
index 63a2425b87..396109e576 100644
--- a/modules/gdnative/gdnative/packed_arrays.cpp
+++ b/modules/gdnative/gdnative/packed_arrays.cpp
@@ -59,6 +59,10 @@ void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self) {
memnew_placement(p_self, PackedByteArray);
}
+void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src) {
+ memnew_placement(r_dest, PackedByteArray(*(PackedByteArray *)p_src));
+}
+
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self) {
((PackedByteArray *)p_self)->~PackedByteArray();
}
@@ -79,6 +83,10 @@ void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self) {
memnew_placement(p_self, PackedInt32Array);
}
+void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src) {
+ memnew_placement(r_dest, PackedInt32Array(*(PackedInt32Array *)p_src));
+}
+
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self) {
((PackedInt32Array *)p_self)->~PackedInt32Array();
}
@@ -99,6 +107,10 @@ void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self) {
memnew_placement(p_self, PackedInt64Array);
}
+void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src) {
+ memnew_placement(r_dest, PackedInt64Array(*(PackedInt64Array *)p_src));
+}
+
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self) {
((PackedInt64Array *)p_self)->~PackedInt64Array();
}
@@ -119,6 +131,10 @@ void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self) {
memnew_placement(p_self, PackedFloat32Array);
}
+void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src) {
+ memnew_placement(r_dest, PackedFloat32Array(*(PackedFloat32Array *)p_src));
+}
+
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self) {
((PackedFloat32Array *)p_self)->~PackedFloat32Array();
}
@@ -139,6 +155,10 @@ void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self) {
memnew_placement(p_self, PackedFloat64Array);
}
+void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src) {
+ memnew_placement(r_dest, PackedFloat64Array(*(PackedFloat64Array *)p_src));
+}
+
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self) {
((PackedFloat64Array *)p_self)->~PackedFloat64Array();
}
@@ -159,6 +179,10 @@ void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self) {
memnew_placement(p_self, PackedStringArray);
}
+void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src) {
+ memnew_placement(r_dest, PackedStringArray(*(PackedStringArray *)p_src));
+}
+
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self) {
((PackedStringArray *)p_self)->~PackedStringArray();
}
@@ -179,6 +203,10 @@ void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self) {
memnew_placement(p_self, PackedVector2Array);
}
+void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src) {
+ memnew_placement(r_dest, PackedVector2Array(*(PackedVector2Array *)p_src));
+}
+
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self) {
((PackedVector2Array *)p_self)->~PackedVector2Array();
}
@@ -199,6 +227,10 @@ void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self)
memnew_placement(p_self, Vector<Vector2i>);
}
+void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src) {
+ memnew_placement(r_dest, Vector<Vector2i>(*(Vector<Vector2i> *)p_src));
+}
+
void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self) {
((Vector<Vector2i> *)p_self)->~Vector();
}
@@ -219,6 +251,10 @@ void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self) {
memnew_placement(p_self, PackedVector3Array);
}
+void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src) {
+ memnew_placement(r_dest, PackedVector3Array(*(PackedVector3Array *)p_src));
+}
+
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self) {
((PackedVector3Array *)p_self)->~PackedVector3Array();
}
@@ -239,6 +275,10 @@ void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self)
memnew_placement(p_self, Vector<Vector3i>);
}
+void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src) {
+ memnew_placement(r_dest, Vector<Vector3i>(*(Vector<Vector3i> *)p_src));
+}
+
void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self) {
((Vector<Vector3i> *)p_self)->~Vector();
}
@@ -259,6 +299,10 @@ void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self) {
memnew_placement(p_self, PackedColorArray);
}
+void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src) {
+ memnew_placement(r_dest, PackedColorArray(*(PackedColorArray *)p_src));
+}
+
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self) {
((PackedColorArray *)p_self)->~PackedColorArray();
}
diff --git a/modules/gdnative/gdnative/plane.cpp b/modules/gdnative/gdnative/plane.cpp
index 61d5e09fad..8b8e84e3c1 100644
--- a/modules/gdnative/gdnative/plane.cpp
+++ b/modules/gdnative/gdnative/plane.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_plane_new(godot_plane *p_self) {
memnew_placement(p_self, Plane);
}
+void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src) {
+ memnew_placement(r_dest, Plane(*(Plane *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp
index 836d6390d6..8ebcf7c91f 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quat.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_quat_new(godot_quat *p_self) {
memnew_placement(p_self, Quat);
}
+void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src) {
+ memnew_placement(r_dest, Quat(*(Quat *)p_src));
+}
+
godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index) {
Quat *self = (Quat *)p_self;
return (godot_real_t *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 086592ec22..a196a63188 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -43,10 +43,18 @@ void GDAPI godot_rect2_new(godot_rect2 *p_self) {
memnew_placement(p_self, Rect2);
}
+void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src) {
+ memnew_placement(r_dest, Rect2(*(Rect2 *)p_src));
+}
+
void GDAPI godot_rect2i_new(godot_rect2i *p_self) {
memnew_placement(p_self, Rect2i);
}
+void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src) {
+ memnew_placement(r_dest, Rect2i(*(Rect2i *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/rid.cpp b/modules/gdnative/gdnative/rid.cpp
index 5cab9a21ed..f8599afcf9 100644
--- a/modules/gdnative/gdnative/rid.cpp
+++ b/modules/gdnative/gdnative/rid.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_rid_new(godot_rid *p_self) {
memnew_placement(p_self, RID);
}
+void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src) {
+ memnew_placement(r_dest, RID(*(RID *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/signal.cpp b/modules/gdnative/gdnative/signal.cpp
index bcb4c93b62..5963c0e6c6 100644
--- a/modules/gdnative/gdnative/signal.cpp
+++ b/modules/gdnative/gdnative/signal.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_signal_new(godot_signal *p_self) {
memnew_placement(p_self, Signal);
}
+void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src) {
+ memnew_placement(r_dest, Signal(*(Signal *)p_src));
+}
+
void GDAPI godot_signal_destroy(godot_signal *p_self) {
Signal *self = (Signal *)p_self;
self->~Signal();
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 19d95f2048..1ad1ea8bdf 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -45,10 +45,7 @@ void GDAPI godot_string_new(godot_string *r_dest) {
}
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src) {
- String *dest = (String *)r_dest;
- const String *src = (const String *)p_src;
- memnew_placement(dest, String);
- *dest = String(*src);
+ memnew_placement(r_dest, String(*(String *)p_src));
}
void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents) {
@@ -125,6 +122,45 @@ void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const
}
}
+const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->ascii(true).get_data();
+}
+
+const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->utf8().get_data();
+}
+
+const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->utf16().get_data();
+}
+
+const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->get_data();
+}
+
+const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ if (sizeof(wchar_t) == 2) {
+ return (const wchar_t *)self->utf16().get_data();
+ } else {
+ return (const wchar_t *)self->get_data();
+ }
+}
+
+char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index) {
+ String *self = (String *)p_self;
+ return self->ptrw();
+}
+
+const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index) {
+ const String *self = (const String *)p_self;
+ return self->ptr();
+}
+
void GDAPI godot_string_destroy(godot_string *p_self) {
String *self = (String *)p_self;
self->~String();
diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/gdnative/gdnative/string_name.cpp
index c9d2dd5bc3..bd8f69674e 100644
--- a/modules/gdnative/gdnative/string_name.cpp
+++ b/modules/gdnative/gdnative/string_name.cpp
@@ -44,9 +44,7 @@ void GDAPI godot_string_name_new(godot_string_name *r_dest) {
}
void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src) {
- StringName *dest = (StringName *)r_dest;
- const StringName *src = (const StringName *)p_src;
- memnew_placement(dest, StringName(*src));
+ memnew_placement(r_dest, StringName(*(StringName *)p_src));
}
void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents) {
diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform.cpp
index eae981bd07..bfaaa13db2 100644
--- a/modules/gdnative/gdnative/transform.cpp
+++ b/modules/gdnative/gdnative/transform.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_transform_new(godot_transform *p_self) {
memnew_placement(p_self, Transform);
}
+void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src) {
+ memnew_placement(r_dest, Transform(*(Transform *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp
index 679174d5a5..2864818831 100644
--- a/modules/gdnative/gdnative/transform2d.cpp
+++ b/modules/gdnative/gdnative/transform2d.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_transform2d_new(godot_transform2d *p_self) {
memnew_placement(p_self, Transform2D);
}
+void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src) {
+ memnew_placement(r_dest, Transform2D(*(Transform2D *)p_src));
+}
+
godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index) {
Transform2D *self = (Transform2D *)p_self;
return (godot_vector2 *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index ee4353bb48..7801e21ab2 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -577,6 +577,54 @@ void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_
}
}
+void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant *self = (Variant *)p_self;
+ const StringName method(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ self->call(method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant::Type type = (Variant::Type)p_type;
+ const StringName *method = (const StringName *)p_method;
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ Variant::call_static(type, *method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant::Type type = (Variant::Type)p_type;
+ const StringName method(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ Variant::call_static(type, method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid) {
Variant::Operator op = (Variant::Operator)p_op;
const Variant *a = (const Variant *)p_a;
@@ -593,12 +641,20 @@ void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key,
self->set(*key, *value, r_valid);
}
-void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid) {
+void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_key, const godot_variant *p_value, bool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const StringName *key = (const StringName *)p_key;
+ const Variant *value = (const Variant *)p_value;
+
+ self->set_named(*key, *value, *r_valid);
+}
+
+void GDAPI godot_variant_set_named_with_cstring(godot_variant *p_self, const char *p_key, const godot_variant *p_value, bool *r_valid) {
Variant *self = (Variant *)p_self;
- const StringName *name = (const StringName *)p_name;
+ const StringName key(p_key);
const Variant *value = (const Variant *)p_value;
- self->set_named(*name, *value, *r_valid);
+ self->set_named(key, *value, *r_valid);
}
void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) {
@@ -638,6 +694,17 @@ godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const g
return result;
}
+godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_self, const char *p_key, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const StringName *key = (const StringName *)p_key;
+ Variant ret;
+
+ ret = self->get_named(*key, *r_valid);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
+}
+
godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) {
const Variant *self = (const Variant *)p_self;
const Variant *key = (const Variant *)p_key;
@@ -824,6 +891,14 @@ bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type
return Variant::is_builtin_method_const((Variant::Type)p_type, StringName(p_method));
}
+bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::is_builtin_method_static((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::is_builtin_method_static((Variant::Type)p_type, StringName(p_method));
+}
+
bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method) {
return Variant::is_builtin_method_vararg((Variant::Type)p_type, *((const StringName *)p_method));
}
diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp
index ebb1996649..6a01a7ad59 100644
--- a/modules/gdnative/gdnative/vector2.cpp
+++ b/modules/gdnative/gdnative/vector2.cpp
@@ -43,10 +43,18 @@ void GDAPI godot_vector2_new(godot_vector2 *p_self) {
memnew_placement(p_self, Vector2);
}
+void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src) {
+ memnew_placement(r_dest, Vector2(*(Vector2 *)p_src));
+}
+
void GDAPI godot_vector2i_new(godot_vector2i *p_self) {
memnew_placement(p_self, Vector2i);
}
+void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src) {
+ memnew_placement(r_dest, Vector2i(*(Vector2i *)p_src));
+}
+
godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index) {
Vector2 *self = (Vector2 *)p_self;
return (godot_real_t *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp
index 0fe1b292a7..fb426c8ac4 100644
--- a/modules/gdnative/gdnative/vector3.cpp
+++ b/modules/gdnative/gdnative/vector3.cpp
@@ -43,10 +43,18 @@ void GDAPI godot_vector3_new(godot_vector3 *p_self) {
memnew_placement(p_self, Vector3);
}
+void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src) {
+ memnew_placement(r_dest, Vector3(*(Vector3 *)p_src));
+}
+
void GDAPI godot_vector3i_new(godot_vector3i *p_self) {
memnew_placement(p_self, Vector3i);
}
+void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src) {
+ memnew_placement(r_dest, Vector3i(*(Vector3i *)p_src));
+}
+
godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index) {
Vector3 *self = (Vector3 *)p_self;
return (godot_real_t *)&self->operator[](p_index);
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index c163fbbc1b..59b078f2b6 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -1143,6 +1143,36 @@
]
},
{
+ "name": "godot_variant_call_with_cstring",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "const godot_int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant *",
+ "r_return"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_evaluate",
"return_type": "void",
"arguments": [
@@ -1200,7 +1230,29 @@
],
[
"const godot_string_name *",
- "p_name"
+ "p_key"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set_named_with_cstring",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_key"
],
[
"const godot_variant *",
@@ -1297,6 +1349,24 @@
]
},
{
+ "name": "godot_variant_get_named_with_cstring",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_get_keyed",
"return_type": "godot_variant",
"arguments": [
@@ -1815,6 +1885,34 @@
]
},
{
+ "name": "godot_variant_is_builtin_method_static",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_static_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_is_builtin_method_vararg",
"return_type": "bool",
"arguments": [
@@ -2752,6 +2850,20 @@
]
},
{
+ "name": "godot_aabb_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_aabb *",
+ "r_dest"
+ ],
+ [
+ "const godot_aabb *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_array_new",
"return_type": "void",
"arguments": [
@@ -2762,6 +2874,20 @@
]
},
{
+ "name": "godot_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_array_destroy",
"return_type": "void",
"arguments": [
@@ -2810,6 +2936,20 @@
]
},
{
+ "name": "godot_basis_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_basis *",
+ "r_dest"
+ ],
+ [
+ "const godot_basis *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_basis_operator_index",
"return_type": "godot_vector3 *",
"arguments": [
@@ -2848,6 +2988,20 @@
]
},
{
+ "name": "godot_callable_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_callable *",
+ "r_dest"
+ ],
+ [
+ "const godot_callable *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_callable_destroy",
"return_type": "void",
"arguments": [
@@ -2868,6 +3022,20 @@
]
},
{
+ "name": "godot_color_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_color *",
+ "r_dest"
+ ],
+ [
+ "const godot_color *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_color_operator_index",
"return_type": "float *",
"arguments": [
@@ -2906,6 +3074,20 @@
]
},
{
+ "name": "godot_dictionary_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_dictionary *",
+ "r_dest"
+ ],
+ [
+ "const godot_dictionary *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_dictionary_destroy",
"return_type": "void",
"arguments": [
@@ -2954,6 +3136,20 @@
]
},
{
+ "name": "godot_node_path_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_node_path *",
+ "r_dest"
+ ],
+ [
+ "const godot_node_path *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_node_path_destroy",
"return_type": "void",
"arguments": [
@@ -2974,6 +3170,20 @@
]
},
{
+ "name": "godot_packed_byte_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_byte_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_byte_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_byte_array_destroy",
"return_type": "void",
"arguments": [
@@ -3022,6 +3232,20 @@
]
},
{
+ "name": "godot_packed_int32_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int32_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int32_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int32_array_destroy",
"return_type": "void",
"arguments": [
@@ -3070,6 +3294,20 @@
]
},
{
+ "name": "godot_packed_int64_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int64_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int64_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int64_array_destroy",
"return_type": "void",
"arguments": [
@@ -3118,6 +3356,20 @@
]
},
{
+ "name": "godot_packed_float32_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float32_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float32_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float32_array_destroy",
"return_type": "void",
"arguments": [
@@ -3166,6 +3418,20 @@
]
},
{
+ "name": "godot_packed_float64_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float64_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float64_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float64_array_destroy",
"return_type": "void",
"arguments": [
@@ -3214,6 +3480,20 @@
]
},
{
+ "name": "godot_packed_string_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_string_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_string_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_string_array_destroy",
"return_type": "void",
"arguments": [
@@ -3262,6 +3542,20 @@
]
},
{
+ "name": "godot_packed_vector2_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector2_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2_array_destroy",
"return_type": "void",
"arguments": [
@@ -3310,6 +3604,20 @@
]
},
{
+ "name": "godot_packed_vector2i_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2i_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector2i_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2i_array_destroy",
"return_type": "void",
"arguments": [
@@ -3358,6 +3666,20 @@
]
},
{
+ "name": "godot_packed_vector3_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector3_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector3_array_destroy",
"return_type": "void",
"arguments": [
@@ -3406,6 +3728,20 @@
]
},
{
+ "name": "godot_packed_vector3i_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3i_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector3i_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector3i_array_destroy",
"return_type": "void",
"arguments": [
@@ -3454,6 +3790,20 @@
]
},
{
+ "name": "godot_packed_color_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_color_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_color_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_color_array_destroy",
"return_type": "void",
"arguments": [
@@ -3502,6 +3852,20 @@
]
},
{
+ "name": "godot_plane_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_plane *",
+ "r_dest"
+ ],
+ [
+ "const godot_plane *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_quat_new",
"return_type": "void",
"arguments": [
@@ -3512,6 +3876,20 @@
]
},
{
+ "name": "godot_quat_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_quat *",
+ "r_dest"
+ ],
+ [
+ "const godot_quat *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_quat_operator_index",
"return_type": "godot_real_t *",
"arguments": [
@@ -3550,6 +3928,20 @@
]
},
{
+ "name": "godot_rect2_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2 *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_rect2i_new",
"return_type": "void",
"arguments": [
@@ -3560,6 +3952,20 @@
]
},
{
+ "name": "godot_rect2i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2i *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_rid_new",
"return_type": "void",
"arguments": [
@@ -3570,6 +3976,20 @@
]
},
{
+ "name": "godot_rid_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rid *",
+ "r_dest"
+ ],
+ [
+ "const godot_rid *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_signal_new",
"return_type": "void",
"arguments": [
@@ -3580,6 +4000,20 @@
]
},
{
+ "name": "godot_signal_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_signal *",
+ "r_dest"
+ ],
+ [
+ "const godot_signal *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_signal_destroy",
"return_type": "void",
"arguments": [
@@ -3784,6 +4218,84 @@
]
},
{
+ "name": "godot_string_to_latin1_chars",
+ "return_type": "const char *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf8_chars",
+ "return_type": "const char *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf16_chars",
+ "return_type": "const char16_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf32_chars",
+ "return_type": "const char32_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_wide_chars",
+ "return_type": "const wchar_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index",
+ "return_type": "char32_t *",
+ "arguments": [
+ [
+ "godot_string *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index_const",
+ "return_type": "const char32_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_string_name_new",
"return_type": "void",
"arguments": [
@@ -3842,6 +4354,20 @@
]
},
{
+ "name": "godot_transform_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_transform2d_new",
"return_type": "void",
"arguments": [
@@ -3852,6 +4378,20 @@
]
},
{
+ "name": "godot_transform2d_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform2d *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform2d *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_transform2d_operator_index",
"return_type": "godot_vector2 *",
"arguments": [
@@ -3890,6 +4430,20 @@
]
},
{
+ "name": "godot_vector2_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2 *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_vector2_operator_index",
"return_type": "godot_real_t *",
"arguments": [
@@ -3928,6 +4482,20 @@
]
},
{
+ "name": "godot_vector2i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2i *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_vector2i_operator_index",
"return_type": "int32_t *",
"arguments": [
@@ -3966,6 +4534,20 @@
]
},
{
+ "name": "godot_vector3_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3 *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_vector3_operator_index",
"return_type": "godot_real_t *",
"arguments": [
@@ -4004,6 +4586,20 @@
]
},
{
+ "name": "godot_vector3i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3i *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_vector3i_operator_index",
"return_type": "int32_t *",
"arguments": [
diff --git a/modules/gdnative/include/gdnative/aabb.h b/modules/gdnative/include/gdnative/aabb.h
index be0235221f..860675065d 100644
--- a/modules/gdnative/include/gdnative/aabb.h
+++ b/modules/gdnative/include/gdnative/aabb.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_aabb_new(godot_aabb *p_self);
+void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index 7603edaa73..bf4b852449 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -50,6 +50,7 @@ typedef struct {
#include <gdnative/variant_struct.h>
void GDAPI godot_array_new(godot_array *p_self);
+void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src);
void GDAPI godot_array_destroy(godot_array *p_self);
godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, godot_int p_index);
const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index af8d7cbdd3..5477dbf811 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_basis_new(godot_basis *p_self);
+void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src);
godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index);
const godot_vector3 GDAPI *godot_basis_operator_index_const(const godot_basis *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h
index 6f359ada5e..b84b0c1f1f 100644
--- a/modules/gdnative/include/gdnative/callable.h
+++ b/modules/gdnative/include/gdnative/callable.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_callable_new(godot_callable *p_self);
+void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src);
void GDAPI godot_callable_destroy(godot_callable *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 17a021e6ea..3334013147 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -50,6 +50,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_color_new(godot_color *p_self);
+void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src);
float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index);
const float GDAPI *godot_color_operator_index_const(const godot_color *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index d2afbc4c94..b9525fb5e6 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -50,6 +50,7 @@ typedef struct {
#include <gdnative/variant_struct.h>
void GDAPI godot_dictionary_new(godot_dictionary *p_self);
+void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src);
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self);
godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key);
const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key);
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 3c31b9a98f..a4607c0152 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_node_path_new(godot_node_path *p_self);
+void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src);
void GDAPI godot_node_path_destroy(godot_node_path *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/packed_arrays.h b/modules/gdnative/include/gdnative/packed_arrays.h
index 621ed60cdf..f9e4ba3a8d 100644
--- a/modules/gdnative/include/gdnative/packed_arrays.h
+++ b/modules/gdnative/include/gdnative/packed_arrays.h
@@ -163,6 +163,7 @@ typedef struct {
// Byte.
void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self);
+void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src);
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self);
uint8_t GDAPI *godot_packed_byte_array_operator_index(godot_packed_byte_array *p_self, godot_int p_index);
const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_packed_byte_array *p_self, godot_int p_index);
@@ -170,6 +171,7 @@ const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_pa
// Int32.
void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self);
+void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src);
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self);
int32_t GDAPI *godot_packed_int32_array_operator_index(godot_packed_int32_array *p_self, godot_int p_index);
const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_packed_int32_array *p_self, godot_int p_index);
@@ -177,6 +179,7 @@ const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_p
// Int64.
void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self);
+void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src);
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self);
int64_t GDAPI *godot_packed_int64_array_operator_index(godot_packed_int64_array *p_self, godot_int p_index);
const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_packed_int64_array *p_self, godot_int p_index);
@@ -184,6 +187,7 @@ const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_p
// Float32.
void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self);
+void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src);
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self);
float GDAPI *godot_packed_float32_array_operator_index(godot_packed_float32_array *p_self, godot_int p_index);
const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_packed_float32_array *p_self, godot_int p_index);
@@ -191,6 +195,7 @@ const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_p
// Float64.
void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self);
+void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src);
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self);
double GDAPI *godot_packed_float64_array_operator_index(godot_packed_float64_array *p_self, godot_int p_index);
const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_packed_float64_array *p_self, godot_int p_index);
@@ -198,6 +203,7 @@ const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_
// String.
void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self);
+void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src);
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self);
godot_string GDAPI *godot_packed_string_array_operator_index(godot_packed_string_array *p_self, godot_int p_index);
const godot_string GDAPI *godot_packed_string_array_operator_index_const(const godot_packed_string_array *p_self, godot_int p_index);
@@ -205,6 +211,7 @@ const godot_string GDAPI *godot_packed_string_array_operator_index_const(const g
// Vector2.
void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self);
+void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src);
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self);
godot_vector2 GDAPI *godot_packed_vector2_array_operator_index(godot_packed_vector2_array *p_self, godot_int p_index);
const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const godot_packed_vector2_array *p_self, godot_int p_index);
@@ -212,6 +219,7 @@ const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const
// Vector2i.
void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self);
+void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src);
void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self);
godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index(godot_packed_vector2i_array *p_self, godot_int p_index);
const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(const godot_packed_vector2i_array *p_self, godot_int p_index);
@@ -219,6 +227,7 @@ const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(con
// Vector3.
void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self);
+void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src);
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self);
godot_vector3 GDAPI *godot_packed_vector3_array_operator_index(godot_packed_vector3_array *p_self, godot_int p_index);
const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const godot_packed_vector3_array *p_self, godot_int p_index);
@@ -226,6 +235,7 @@ const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const
// Vector3i.
void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self);
+void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src);
void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self);
godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index(godot_packed_vector3i_array *p_self, godot_int p_index);
const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(const godot_packed_vector3i_array *p_self, godot_int p_index);
@@ -233,6 +243,7 @@ const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(con
// Color.
void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self);
+void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src);
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self);
godot_color GDAPI *godot_packed_color_array_operator_index(godot_packed_color_array *p_self, godot_int p_index);
const godot_color GDAPI *godot_packed_color_array_operator_index_const(const godot_packed_color_array *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h
index ed10955e5f..6cd0ed6307 100644
--- a/modules/gdnative/include/gdnative/plane.h
+++ b/modules/gdnative/include/gdnative/plane.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_plane_new(godot_plane *p_self);
+void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index 69bf427611..00abdb4404 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_quat_new(godot_quat *p_self);
+void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src);
godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index);
const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 9e51254cfe..326462be43 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -58,7 +58,9 @@ typedef struct godot_rect2i {
#include <gdnative/gdnative.h>
void GDAPI godot_rect2_new(godot_rect2 *p_self);
+void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src);
void GDAPI godot_rect2i_new(godot_rect2i *p_self);
+void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h
index 7ea8cfd174..bc832fbeb9 100644
--- a/modules/gdnative/include/gdnative/rid.h
+++ b/modules/gdnative/include/gdnative/rid.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_rid_new(godot_rid *p_self);
+void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h
index ad84542677..f4dc17e089 100644
--- a/modules/gdnative/include/gdnative/signal.h
+++ b/modules/gdnative/include/gdnative/signal.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_signal_new(godot_signal *p_self);
+void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src);
void GDAPI godot_signal_destroy(godot_signal *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index 10fbb2c078..79de52c80f 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -55,6 +55,7 @@ typedef struct {
#endif
#include <gdnative/gdnative.h>
+#include <gdnative/math_defs.h>
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
@@ -72,6 +73,15 @@ void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const
void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size);
void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
+const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self);
+const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self);
+const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self);
+const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self);
+const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self);
+
+char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index);
+const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h
index e67862d140..3861b5683a 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/transform.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_transform_new(godot_transform *p_self);
+void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h
index 4a2bca7cfc..5acb172081 100644
--- a/modules/gdnative/include/gdnative/transform2d.h
+++ b/modules/gdnative/include/gdnative/transform2d.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_transform2d_new(godot_transform2d *p_self);
+void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src);
godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index);
const godot_vector2 GDAPI *godot_transform2d_operator_index_const(const godot_transform2d *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 329a6faf51..3e06ed9aa4 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -272,6 +272,8 @@ void GDAPI godot_variant_destroy(godot_variant *p_self);
void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid);
void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid);
void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid);
@@ -323,6 +325,8 @@ godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_vari
godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method);
bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method);
bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method);
+bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method);
bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method);
bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method);
int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type);
diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h
index 5ebb705ba4..00faffbad7 100644
--- a/modules/gdnative/include/gdnative/vector2.h
+++ b/modules/gdnative/include/gdnative/vector2.h
@@ -58,7 +58,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_vector2_new(godot_vector2 *p_self);
+void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src);
void GDAPI godot_vector2i_new(godot_vector2i *p_self);
+void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src);
godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index);
const godot_real_t GDAPI *godot_vector2_operator_index_const(const godot_vector2 *p_self, godot_int p_index);
int32_t GDAPI *godot_vector2i_operator_index(godot_vector2i *p_self, godot_int p_index);
diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h
index d37ebd3cc9..7db093ce52 100644
--- a/modules/gdnative/include/gdnative/vector3.h
+++ b/modules/gdnative/include/gdnative/vector3.h
@@ -58,7 +58,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_vector3_new(godot_vector3 *p_self);
+void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src);
void GDAPI godot_vector3i_new(godot_vector3i *p_self);
+void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src);
godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index);
const godot_real_t GDAPI *godot_vector3_operator_index_const(const godot_vector3 *p_self, godot_int p_index);
int32_t GDAPI *godot_vector3i_operator_index(godot_vector3i *p_self, godot_int p_index);
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 3e75478cd8..f184c84615 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -71,6 +71,7 @@ struct MethodAPI {
bool is_editor = false;
bool is_noscript = false;
bool is_const = false;
+ bool is_static = false; // For builtin types.
bool is_reverse = false;
bool is_virtual = false;
bool is_from_script = false;
@@ -528,6 +529,7 @@ List<ClassAPI> generate_c_builtin_api_types() {
method_api.argument_count = Variant::get_builtin_method_argument_count(type, method_name);
method_api.has_varargs = Variant::is_builtin_method_vararg(type, method_name);
method_api.is_const = Variant::is_builtin_method_const(type, method_name);
+ method_api.is_static = Variant::is_builtin_method_static(type, method_name);
for (int i = 0; i < method_api.argument_count; i++) {
method_api.argument_names.push_back(Variant::get_builtin_method_argument_name(type, method_name, i));
@@ -757,6 +759,7 @@ static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_met
append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name));
append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type));
append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false"));
+ append_indented(p_source, vformat(R"("is_static": %s,)", p_method.is_static ? "true" : "false"));
append_indented(p_source, vformat(R"("has_varargs": %s,)", p_method.has_varargs ? "true" : "false"));
append_indented(p_source, R"("arguments": [)");
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 1bdbb0b03b..0025f4bb06 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -173,7 +173,7 @@ bool NativeScript::can_instance() const {
#ifdef TOOLS_ENABLED
// Only valid if this is either a tool script or a "regular" script.
- // (so an environment whre scripting is disabled (and not the editor) would not
+ // (so, an environment where scripting is disabled (and not the editor) would not
// create objects).
return script_data && (is_tool() || ScriptServer::is_scripting_enabled());
#else
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 31f4fecb19..d08bde9e23 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -142,7 +142,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty
}
}
- // Add symbols for staticaly linked libraries on iOS
+ // Add symbols for statically linked libraries on iOS
if (p_features.has("iOS")) {
bool should_fake_dynamic = false;
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index af76d9a4cc..39f208c7a4 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -145,9 +145,13 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
if (p_active) {
if (!map_is_active(p_map)) {
active_maps.push_back(map);
+ active_maps_update_id.push_back(map->get_map_update_id());
}
} else {
- active_maps.erase(map);
+ int map_index = active_maps.find(map);
+ ERR_FAIL_COND(map_index < 0);
+ active_maps.remove(map_index);
+ active_maps_update_id.remove(map_index);
}
}
@@ -304,6 +308,27 @@ void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p
#endif
}
+int GdNavigationServer::region_get_connections_count(RID p_region) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, 0);
+
+ return region->get_connections_count();
+}
+
+Vector3 GdNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, Vector3());
+
+ return region->get_connection_pathway_start(p_connection_id);
+}
+
+Vector3 GdNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, Vector3());
+
+ return region->get_connection_pathway_end(p_connection_id);
+}
+
RID GdNavigationServer::agent_create() const {
auto mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
@@ -443,7 +468,9 @@ COMMAND_1(free, RID, p_object) {
agents[i]->set_map(nullptr);
}
- active_maps.erase(map);
+ int map_index = active_maps.find(map);
+ active_maps.remove(map_index);
+ active_maps_update_id.remove(map_index);
map_owner.free(p_object);
memdelete(map);
@@ -504,10 +531,17 @@ void GdNavigationServer::process(real_t p_delta_time) {
// In c++ we can't be sure that this is performed in the main thread
// even with mutable functions.
MutexLock lock(operations_mutex);
- for (int i(0); i < active_maps.size(); i++) {
+ for (uint32_t i(0); i < active_maps.size(); i++) {
active_maps[i]->sync();
active_maps[i]->step(p_delta_time);
active_maps[i]->dispatch_callbacks();
+
+ // Emit a signal if a map changed.
+ const uint32_t new_map_update_id = active_maps[i]->get_map_update_id();
+ if (new_map_update_id != active_maps_update_id[i]) {
+ emit_signal("map_changed", active_maps[i]->get_self());
+ active_maps_update_id[i] = new_map_update_id;
+ }
}
}
diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/gdnavigation/gd_navigation_server.h
index 8bc65eccab..2f51f6431e 100644
--- a/modules/gdnavigation/gd_navigation_server.h
+++ b/modules/gdnavigation/gd_navigation_server.h
@@ -31,6 +31,7 @@
#ifndef GD_NAVIGATION_SERVER_H
#define GD_NAVIGATION_SERVER_H
+#include "core/templates/local_vector.h"
#include "core/templates/rid.h"
#include "core/templates/rid_owner.h"
#include "servers/navigation_server_3d.h"
@@ -79,7 +80,8 @@ class GdNavigationServer : public NavigationServer3D {
mutable RID_PtrOwner<RvoAgent> agent_owner;
bool active = true;
- Vector<NavMap *> active_maps;
+ LocalVector<NavMap *> active_maps;
+ LocalVector<uint32_t> active_maps_update_id;
public:
GdNavigationServer();
@@ -114,6 +116,9 @@ public:
COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
+ virtual int region_get_connections_count(RID p_region) const;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
virtual RID agent_create() const;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 5289975e4b..80f367f3a6 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -40,7 +40,7 @@
@author AndreaCatania
*/
-#define USE_ENTRY_POINT
+#define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a)))
void NavMap::set_up(Vector3 p_up) {
up = p_up;
@@ -71,13 +71,13 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
}
Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
+ // Find the start poly and the end poly on this map.
const gd::Polygon *begin_poly = nullptr;
const gd::Polygon *end_poly = nullptr;
Vector3 begin_point;
Vector3 end_point;
float begin_d = 1e20;
float end_d = 1e20;
-
// Find the initial poly and the end poly on this map.
for (size_t i(0); i < polygons.size(); i++) {
const gd::Polygon &p = polygons[i];
@@ -88,31 +88,34 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
// For each point cast a face and check the distance between the origin/destination
- for (size_t point_id = 2; point_id < p.points.size(); point_id++) {
- Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
- Vector3 spoint = f.get_closest_point_to(p_origin);
- float dpoint = spoint.distance_to(p_origin);
- if (dpoint < begin_d) {
- begin_d = dpoint;
+ for (size_t point_id = 0; point_id < p.points.size(); point_id++) {
+ const Vector3 p1 = p.points[point_id].pos;
+ const Vector3 p2 = p.points[(point_id + 1) % p.points.size()].pos;
+ const Vector3 p3 = p.points[(point_id + 2) % p.points.size()].pos;
+ const Face3 face(p1, p2, p3);
+
+ Vector3 point = face.get_closest_point_to(p_origin);
+ float distance_to_point = point.distance_to(p_origin);
+ if (distance_to_point < begin_d) {
+ begin_d = distance_to_point;
begin_poly = &p;
- begin_point = spoint;
+ begin_point = point;
}
- spoint = f.get_closest_point_to(p_destination);
- dpoint = spoint.distance_to(p_destination);
- if (dpoint < end_d) {
- end_d = dpoint;
+ point = face.get_closest_point_to(p_destination);
+ distance_to_point = point.distance_to(p_destination);
+ if (distance_to_point < end_d) {
+ end_d = distance_to_point;
end_poly = &p;
- end_point = spoint;
+ end_point = point;
}
}
}
+ // Check for trival cases
if (!begin_poly || !end_poly) {
- // No path
return Vector<Vector3>();
}
-
if (begin_poly == end_poly) {
Vector<Vector3> path;
path.resize(2);
@@ -121,95 +124,89 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
return path;
}
+ // List of all reachable navigation polys.
std::vector<gd::NavigationPoly> navigation_polys;
navigation_polys.reserve(polygons.size() * 0.75);
- // The elements indices in the `navigation_polys`.
- int least_cost_id(-1);
- List<uint32_t> open_list;
- bool found_route = false;
+ // Add the start polygon to the reachable navigation polygons.
+ gd::NavigationPoly begin_navigation_poly = gd::NavigationPoly(begin_poly);
+ begin_navigation_poly.self_id = 0;
+ begin_navigation_poly.entry = begin_point;
+ begin_navigation_poly.back_navigation_edge_pathway_start = begin_point;
+ begin_navigation_poly.back_navigation_edge_pathway_end = begin_point;
+ navigation_polys.push_back(begin_navigation_poly);
- navigation_polys.push_back(gd::NavigationPoly(begin_poly));
- {
- least_cost_id = 0;
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
- least_cost_poly->self_id = least_cost_id;
- least_cost_poly->entry = begin_point;
- }
+ // List of polygon IDs to visit.
+ List<uint32_t> to_visit;
+ to_visit.push_back(0);
- open_list.push_back(0);
+ // This is an implementation of the A* algorithm.
+ int least_cost_id = 0;
+ bool found_route = false;
const gd::Polygon *reachable_end = nullptr;
float reachable_d = 1e30;
bool is_reachable = true;
- while (found_route == false) {
- {
- // Takes the current least_cost_poly neighbors and compute the traveled_distance of each
- for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
+ while (true) {
+ gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
- // Only consider the polygon if it in a region with compatible layers.
- if ((p_layers & least_cost_poly->poly->owner->get_layers()) == 0) {
- continue;
- }
+ // Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
+ for (size_t i = 0; i < least_cost_poly->poly->edges.size(); i++) {
+ const gd::Edge &edge = least_cost_poly->poly->edges[i];
+
+ // Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon.
+ for (int connection_index = 0; connection_index < edge.connections.size(); connection_index++) {
+ const gd::Edge::Connection &connection = edge.connections[connection_index];
- const gd::Edge &edge = least_cost_poly->poly->edges[i];
- if (!edge.other_polygon) {
+ // Only consider the connection to another polygon if this polygon is in a region with compatible layers.
+ if ((p_layers & connection.polygon->owner->get_layers()) == 0) {
continue;
}
-#ifdef USE_ENTRY_POINT
- Vector3 edge_line[2] = {
- least_cost_poly->poly->points[i].pos,
- least_cost_poly->poly->points[(i + 1) % least_cost_poly->poly->points.size()].pos
- };
-
- const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, edge_line);
+ Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
+ const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
-#else
- const float new_distance = least_cost_poly->poly->center.distance_to(edge.other_polygon->center) + least_cost_poly->traveled_distance;
-#endif
auto it = std::find(
navigation_polys.begin(),
navigation_polys.end(),
- gd::NavigationPoly(edge.other_polygon));
+ gd::NavigationPoly(connection.polygon));
if (it != navigation_polys.end()) {
- // Oh this was visited already, can we win the cost?
- if (it->traveled_distance > new_distance) {
- it->prev_navigation_poly_id = least_cost_id;
- it->back_navigation_edge = edge.other_edge;
+ // Polygon already visited, check if we can reduce the travel cost.
+ if (new_distance < it->traveled_distance) {
+ it->back_navigation_poly_id = least_cost_id;
+ it->back_navigation_edge = connection.edge;
+ it->back_navigation_edge_pathway_start = connection.pathway_start;
+ it->back_navigation_edge_pathway_end = connection.pathway_end;
it->traveled_distance = new_distance;
-#ifdef USE_ENTRY_POINT
it->entry = new_entry;
-#endif
}
} else {
- // Add to open neighbours
-
- navigation_polys.push_back(gd::NavigationPoly(edge.other_polygon));
- gd::NavigationPoly *np = &navigation_polys[navigation_polys.size() - 1];
-
- np->self_id = navigation_polys.size() - 1;
- np->prev_navigation_poly_id = least_cost_id;
- np->back_navigation_edge = edge.other_edge;
- np->traveled_distance = new_distance;
-#ifdef USE_ENTRY_POINT
- np->entry = new_entry;
-#endif
- open_list.push_back(navigation_polys.size() - 1);
+ // Add the neighbour polygon to the reachable ones.
+ gd::NavigationPoly new_navigation_poly = gd::NavigationPoly(connection.polygon);
+ new_navigation_poly.self_id = navigation_polys.size();
+ new_navigation_poly.back_navigation_poly_id = least_cost_id;
+ new_navigation_poly.back_navigation_edge = connection.edge;
+ new_navigation_poly.back_navigation_edge_pathway_start = connection.pathway_start;
+ new_navigation_poly.back_navigation_edge_pathway_end = connection.pathway_end;
+ new_navigation_poly.traveled_distance = new_distance;
+ new_navigation_poly.entry = new_entry;
+ navigation_polys.push_back(new_navigation_poly);
+
+ // Add the neighbour polygon to the polygons to visit.
+ to_visit.push_back(navigation_polys.size() - 1);
}
}
}
- // Removes the least cost polygon from the open list so we can advance.
- open_list.erase(least_cost_id);
+ // Removes the least cost polygon from the list of polygons to visit so we can advance.
+ to_visit.erase(least_cost_id);
- if (open_list.size() == 0) {
- // When the open list is empty at this point the End Polygon is not reachable
- // so use the further reachable polygon
+ // When the list of polygons to visit is empty at this point it means the End Polygon is not reachable
+ if (to_visit.size() == 0) {
+ // Thus use the further reachable polygon
ERR_BREAK_MSG(is_reachable == false, "It's not expect to not find the most reachable polygons");
is_reachable = false;
if (reachable_end == nullptr) {
@@ -234,26 +231,21 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
gd::NavigationPoly np = navigation_polys[0];
navigation_polys.clear();
navigation_polys.push_back(np);
- open_list.clear();
- open_list.push_back(0);
+ to_visit.clear();
+ to_visit.push_back(0);
reachable_end = nullptr;
continue;
}
- // Now take the new least_cost_poly from the open list.
+ // Find the polygon with the minimum cost from the list of polygons to visit.
least_cost_id = -1;
float least_cost = 1e30;
-
- for (auto element = open_list.front(); element != nullptr; element = element->next()) {
+ for (List<uint32_t>::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
-#ifdef USE_ENTRY_POINT
cost += np->entry.distance_to(end_point);
-#else
- cost += np->poly->center.distance_to(end_point);
-#endif
if (cost < least_cost) {
least_cost_id = np->self_id;
least_cost = cost;
@@ -273,124 +265,108 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Check if we reached the end
if (navigation_polys[least_cost_id].poly == end_poly) {
- // Yep, done!!
found_route = true;
break;
}
}
- if (found_route) {
- Vector<Vector3> path;
- if (p_optimize) {
- // String pulling
-
- gd::NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
- Vector3 apex_point = end_point;
- Vector3 portal_left = apex_point;
- Vector3 portal_right = apex_point;
- gd::NavigationPoly *left_poly = apex_poly;
- gd::NavigationPoly *right_poly = apex_poly;
- gd::NavigationPoly *p = apex_poly;
-
- path.push_back(end_point);
+ // If we did not find a route, return an empty path.
+ if (!found_route) {
+ return Vector<Vector3>();
+ }
- while (p) {
- Vector3 left;
- Vector3 right;
+ Vector<Vector3> path;
+ // Optimize the path.
+ if (p_optimize) {
+ // Set the apex poly/point to the end point
+ gd::NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
+ Vector3 apex_point = end_point;
-#define CLOCK_TANGENT(m_a, m_b, m_c) (((m_a) - (m_c)).cross((m_a) - (m_b)))
+ gd::NavigationPoly *left_poly = apex_poly;
+ Vector3 left_portal = apex_point;
+ gd::NavigationPoly *right_poly = apex_poly;
+ Vector3 right_portal = apex_point;
- if (p->poly == begin_poly) {
- left = begin_point;
- right = begin_point;
- } else {
- int prev = p->back_navigation_edge;
- int prev_n = (p->back_navigation_edge + 1) % p->poly->points.size();
- left = p->poly->points[prev].pos;
- right = p->poly->points[prev_n].pos;
+ gd::NavigationPoly *p = apex_poly;
- if (p->poly->clockwise) {
- SWAP(left, right);
- }
- }
+ path.push_back(end_point);
- bool skip = false;
-
- if (CLOCK_TANGENT(apex_point, portal_left, left).dot(up) >= 0) {
- //process
- if (portal_left == apex_point || CLOCK_TANGENT(apex_point, left, portal_right).dot(up) > 0) {
- left_poly = p;
- portal_left = left;
- } else {
- clip_path(navigation_polys, path, apex_poly, portal_right, right_poly);
-
- apex_point = portal_right;
- p = right_poly;
- left_poly = p;
- apex_poly = p;
- portal_left = apex_point;
- portal_right = apex_point;
- path.push_back(apex_point);
- skip = true;
- }
- }
+ while (p) {
+ // Set left and right points of the pathway between polygons.
+ Vector3 left = p->back_navigation_edge_pathway_start;
+ Vector3 right = p->back_navigation_edge_pathway_end;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left, right).dot(up) < 0) {
+ SWAP(left, right);
+ }
- if (!skip && CLOCK_TANGENT(apex_point, portal_right, right).dot(up) <= 0) {
- //process
- if (portal_right == apex_point || CLOCK_TANGENT(apex_point, right, portal_left).dot(up) < 0) {
- right_poly = p;
- portal_right = right;
- } else {
- clip_path(navigation_polys, path, apex_poly, portal_left, left_poly);
-
- apex_point = portal_left;
- p = left_poly;
- right_poly = p;
- apex_poly = p;
- portal_right = apex_point;
- portal_left = apex_point;
- path.push_back(apex_point);
- }
+ bool skip = false;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left_portal, left).dot(up) >= 0) {
+ //process
+ if (left_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, left, right_portal).dot(up) > 0) {
+ left_poly = p;
+ left_portal = left;
+ } else {
+ clip_path(navigation_polys, path, apex_poly, right_portal, right_poly);
+
+ apex_point = right_portal;
+ p = right_poly;
+ left_poly = p;
+ apex_poly = p;
+ left_portal = apex_point;
+ right_portal = apex_point;
+ path.push_back(apex_point);
+ skip = true;
}
+ }
- if (p->prev_navigation_poly_id != -1) {
- p = &navigation_polys[p->prev_navigation_poly_id];
+ if (!skip && THREE_POINTS_CROSS_PRODUCT(apex_point, right_portal, right).dot(up) <= 0) {
+ //process
+ if (right_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, right, left_portal).dot(up) < 0) {
+ right_poly = p;
+ right_portal = right;
} else {
- // The end
- p = nullptr;
+ clip_path(navigation_polys, path, apex_poly, left_portal, left_poly);
+
+ apex_point = left_portal;
+ p = left_poly;
+ right_poly = p;
+ apex_poly = p;
+ right_portal = apex_point;
+ left_portal = apex_point;
+ path.push_back(apex_point);
}
}
- if (path[path.size() - 1] != begin_point) {
- path.push_back(begin_point);
+ // Go to the previous polygon.
+ if (p->back_navigation_poly_id != -1) {
+ p = &navigation_polys[p->back_navigation_poly_id];
+ } else {
+ // The end
+ p = nullptr;
}
+ }
- path.invert();
-
- } else {
- path.push_back(end_point);
+ // If the last point is not the begin point, add it to the list.
+ if (path[path.size() - 1] != begin_point) {
+ path.push_back(begin_point);
+ }
- // Add mid points
- int np_id = least_cost_id;
- while (np_id != -1) {
-#ifdef USE_ENTRY_POINT
- Vector3 point = navigation_polys[np_id].entry;
-#else
- int prev = navigation_polys[np_id].back_navigation_edge;
- int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
- Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
-#endif
+ path.invert();
- path.push_back(point);
- np_id = navigation_polys[np_id].prev_navigation_poly_id;
- }
+ } else {
+ path.push_back(end_point);
- path.invert();
+ // Add mid points
+ int np_id = least_cost_id;
+ while (np_id != -1) {
+ path.push_back(navigation_polys[np_id].entry);
+ np_id = navigation_polys[np_id].back_navigation_poly_id;
}
- return path;
+ path.invert();
}
- return Vector<Vector3>();
+
+ return path;
}
Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -571,6 +547,7 @@ void NavMap::remove_agent_as_controlled(RvoAgent *agent) {
}
void NavMap::sync() {
+ // Check if we need to update the links.
if (regenerate_polygons) {
for (size_t r(0); r < regions.size(); r++) {
regions[r]->scratch_polygons();
@@ -585,27 +562,30 @@ void NavMap::sync() {
}
if (regenerate_links) {
- // Copy all region polygons in the map.
+ // Remove regions connections.
+ for (size_t r(0); r < regions.size(); r++) {
+ regions[r]->get_connections().clear();
+ }
+
+ // Resize the polygon count.
int count = 0;
for (size_t r(0); r < regions.size(); r++) {
count += regions[r]->get_polygons().size();
}
-
polygons.resize(count);
- count = 0;
+ // Copy all region polygons in the map.
+ count = 0;
for (size_t r(0); r < regions.size(); r++) {
std::copy(
regions[r]->get_polygons().data(),
regions[r]->get_polygons().data() + regions[r]->get_polygons().size(),
polygons.begin() + count);
-
count += regions[r]->get_polygons().size();
}
- // Connects the `Edges` of all the `Polygons` of all `Regions` each other.
- Map<gd::EdgeKey, gd::Connection> connections;
-
+ // Group all edges per key.
+ Map<gd::EdgeKey, Vector<gd::Edge::Connection>> connections;
for (size_t poly_id(0); poly_id < polygons.size(); poly_id++) {
gd::Polygon &poly(polygons[poly_id]);
@@ -613,30 +593,18 @@ void NavMap::sync() {
int next_point = (p + 1) % poly.points.size();
gd::EdgeKey ek(poly.points[p].key, poly.points[next_point].key);
- Map<gd::EdgeKey, gd::Connection>::Element *connection = connections.find(ek);
+ Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *connection = connections.find(ek);
if (!connection) {
- // Nothing yet
- gd::Connection c;
- c.A = &poly;
- c.A_edge = p;
- c.B = nullptr;
- c.B_edge = -1;
- connections[ek] = c;
-
- } else if (connection->get().B == nullptr) {
- CRASH_COND(connection->get().A == nullptr); // Unreachable
-
- // Connect the two Polygons by this edge
- connection->get().B = &poly;
- connection->get().B_edge = p;
-
- connection->get().A->edges[connection->get().A_edge].this_edge = connection->get().A_edge;
- connection->get().A->edges[connection->get().A_edge].other_polygon = connection->get().B;
- connection->get().A->edges[connection->get().A_edge].other_edge = connection->get().B_edge;
-
- connection->get().B->edges[connection->get().B_edge].this_edge = connection->get().B_edge;
- connection->get().B->edges[connection->get().B_edge].other_polygon = connection->get().A;
- connection->get().B->edges[connection->get().B_edge].other_edge = connection->get().A_edge;
+ connections[ek] = Vector<gd::Edge::Connection>();
+ }
+ if (connections[ek].size() <= 1) {
+ // Add the polygon/edge tuple to this key.
+ gd::Edge::Connection new_connection;
+ new_connection.polygon = &poly;
+ new_connection.edge = p;
+ new_connection.pathway_start = poly.points[p].pos;
+ new_connection.pathway_end = poly.points[next_point].pos;
+ connections[ek].push_back(new_connection);
} else {
// The edge is already connected with another edge, skip.
ERR_PRINT("Attempted to merge a navigation mesh triangle edge with another already-merged edge. This happens when the current `cell_size` is different from the one used to generate the navigation mesh. This will cause navigation problem.");
@@ -644,38 +612,21 @@ void NavMap::sync() {
}
}
- // Takes all the free edges.
- std::vector<gd::FreeEdge> free_edges;
- free_edges.reserve(connections.size());
-
- for (auto connection_element = connections.front(); connection_element; connection_element = connection_element->next()) {
- if (connection_element->get().B == nullptr) {
- CRASH_COND(connection_element->get().A == nullptr); // Unreachable
- CRASH_COND(connection_element->get().A_edge < 0); // Unreachable
-
- // This is a free edge
- uint32_t id(free_edges.size());
- free_edges.push_back(gd::FreeEdge());
- free_edges[id].is_free = true;
- free_edges[id].poly = connection_element->get().A;
- free_edges[id].edge_id = connection_element->get().A_edge;
- uint32_t point_0(free_edges[id].edge_id);
- uint32_t point_1((free_edges[id].edge_id + 1) % free_edges[id].poly->points.size());
- Vector3 pos_0 = free_edges[id].poly->points[point_0].pos;
- Vector3 pos_1 = free_edges[id].poly->points[point_1].pos;
- Vector3 relative = pos_1 - pos_0;
- free_edges[id].edge_center = (pos_0 + pos_1) / 2.0;
- free_edges[id].edge_dir = relative.normalized();
- free_edges[id].edge_len_squared = relative.length_squared();
+ Vector<gd::Edge::Connection> free_edges;
+ for (Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *E = connections.front(); E; E = E->next()) {
+ if (E->get().size() == 2) {
+ // Connect edge that are shared in different polygons.
+ gd::Edge::Connection &c1 = E->get().write[0];
+ gd::Edge::Connection &c2 = E->get().write[1];
+ c1.polygon->edges[c1.edge].connections.push_back(c2);
+ c2.polygon->edges[c2.edge].connections.push_back(c1);
+ // Note: The pathway_start/end are full for those connection and do not need to be modified.
+ } else {
+ CRASH_COND_MSG(E->get().size() != 1, vformat("Number of connection != 1. Found: %d", E->get().size()));
+ free_edges.push_back(E->get()[0]);
}
}
- const float ecm_squared(edge_connection_margin * edge_connection_margin);
-#define LEN_TOLLERANCE 0.1
-#define DIR_TOLLERANCE 0.9
- // In front of tolerance
-#define IFO_TOLLERANCE 0.5
-
// Find the compatible near edges.
//
// Note:
@@ -683,43 +634,67 @@ void NavMap::sync() {
// to be connected, create new polygons to remove that small gap is
// not really useful and would result in wasteful computation during
// connection, integration and path finding.
- for (size_t i(0); i < free_edges.size(); i++) {
- if (!free_edges[i].is_free) {
- continue;
- }
- gd::FreeEdge &edge = free_edges[i];
- for (size_t y(0); y < free_edges.size(); y++) {
- gd::FreeEdge &other_edge = free_edges[y];
- if (i == y || !other_edge.is_free || edge.poly->owner == other_edge.poly->owner) {
+ for (int i = 0; i < free_edges.size(); i++) {
+ const gd::Edge::Connection &free_edge = free_edges[i];
+ Vector3 edge_p1 = free_edge.polygon->points[free_edge.edge].pos;
+ Vector3 edge_p2 = free_edge.polygon->points[(free_edge.edge + 1) % free_edge.polygon->points.size()].pos;
+
+ for (int j = 0; j < free_edges.size(); j++) {
+ const gd::Edge::Connection &other_edge = free_edges[j];
+ if (i == j || free_edge.polygon->owner == other_edge.polygon->owner) {
+ continue;
+ }
+
+ Vector3 other_edge_p1 = other_edge.polygon->points[other_edge.edge].pos;
+ Vector3 other_edge_p2 = other_edge.polygon->points[(other_edge.edge + 1) % other_edge.polygon->points.size()].pos;
+
+ // Compute the projection of the opposite edge on the current one
+ Vector3 edge_vector = edge_p2 - edge_p1;
+ float projected_p1_ratio = edge_vector.dot(other_edge_p1 - edge_p1) / (edge_vector.length_squared());
+ float projected_p2_ratio = edge_vector.dot(other_edge_p2 - edge_p1) / (edge_vector.length_squared());
+ if ((projected_p1_ratio < 0.0 && projected_p2_ratio < 0.0) || (projected_p1_ratio > 1.0 && projected_p2_ratio > 1.0)) {
continue;
}
- Vector3 rel_centers = other_edge.edge_center - edge.edge_center;
- if (ecm_squared > rel_centers.length_squared() // Are enough closer?
- && ABS(edge.edge_len_squared - other_edge.edge_len_squared) < LEN_TOLLERANCE // Are the same length?
- && ABS(edge.edge_dir.dot(other_edge.edge_dir)) > DIR_TOLLERANCE // Are aligned?
- && ABS(rel_centers.normalized().dot(edge.edge_dir)) < IFO_TOLLERANCE // Are one in front the other?
- ) {
- // The edges can be connected
- edge.is_free = false;
- other_edge.is_free = false;
-
- edge.poly->edges[edge.edge_id].this_edge = edge.edge_id;
- edge.poly->edges[edge.edge_id].other_edge = other_edge.edge_id;
- edge.poly->edges[edge.edge_id].other_polygon = other_edge.poly;
-
- other_edge.poly->edges[other_edge.edge_id].this_edge = other_edge.edge_id;
- other_edge.poly->edges[other_edge.edge_id].other_edge = edge.edge_id;
- other_edge.poly->edges[other_edge.edge_id].other_polygon = edge.poly;
+ // Check if the two edges are close to each other enough and compute a pathway between the two regions.
+ Vector3 self1 = edge_vector * CLAMP(projected_p1_ratio, 0.0, 1.0) + edge_p1;
+ Vector3 other1;
+ if (projected_p1_ratio >= 0.0 && projected_p1_ratio <= 1.0) {
+ other1 = other_edge_p1;
+ } else {
+ other1 = other_edge_p1.lerp(other_edge_p2, (1.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
+ if ((self1 - other1).length() > edge_connection_margin) {
+ continue;
+ }
+
+ Vector3 self2 = edge_vector * CLAMP(projected_p2_ratio, 0.0, 1.0) + edge_p1;
+ Vector3 other2;
+ if (projected_p2_ratio >= 0.0 && projected_p2_ratio <= 1.0) {
+ other2 = other_edge_p2;
+ } else {
+ other2 = other_edge_p1.lerp(other_edge_p2, (0.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
+ }
+ if ((self2 - other2).length() > edge_connection_margin) {
+ continue;
+ }
+
+ // The edges can now be connected.
+ gd::Edge::Connection new_connection = other_edge;
+ new_connection.pathway_start = (self1 + other1) / 2.0;
+ new_connection.pathway_end = (self2 + other2) / 2.0;
+ free_edge.polygon->edges[free_edge.edge].connections.push_back(new_connection);
+
+ // Add the connection to the region_connection map.
+ free_edge.polygon->owner->get_connections().push_back(new_connection);
}
}
- }
- if (regenerate_links) {
+ // Update the update ID.
map_update_id = (map_update_id + 1) % 9999999;
}
+ // Update agents tree.
if (agents_dirty) {
std::vector<RVO::Agent *> raw_agents;
raw_agents.reserve(agents.size());
@@ -771,16 +746,15 @@ void NavMap::clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys
cut_plane.d = cut_plane.normal.dot(from);
while (from_poly != p_to_poly) {
- int back_nav_edge = from_poly->back_navigation_edge;
- Vector3 a = from_poly->poly->points[back_nav_edge].pos;
- Vector3 b = from_poly->poly->points[(back_nav_edge + 1) % from_poly->poly->points.size()].pos;
+ Vector3 pathway_start = from_poly->back_navigation_edge_pathway_start;
+ Vector3 pathway_end = from_poly->back_navigation_edge_pathway_end;
- ERR_FAIL_COND(from_poly->prev_navigation_poly_id == -1);
- from_poly = &p_navigation_polys[from_poly->prev_navigation_poly_id];
+ ERR_FAIL_COND(from_poly->back_navigation_poly_id == -1);
+ from_poly = &p_navigation_polys[from_poly->back_navigation_poly_id];
- if (a.distance_to(b) > CMP_EPSILON) {
+ if (pathway_start.distance_to(pathway_end) > CMP_EPSILON) {
Vector3 inters;
- if (cut_plane.intersects_segment(a, b, &inters)) {
+ if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) {
if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(path[path.size() - 1]) > CMP_EPSILON) {
path.push_back(inters);
}
diff --git a/modules/gdnavigation/nav_map.h b/modules/gdnavigation/nav_map.h
index 6b7cfae324..8e013a72eb 100644
--- a/modules/gdnavigation/nav_map.h
+++ b/modules/gdnavigation/nav_map.h
@@ -34,6 +34,7 @@
#include "nav_rid.h"
#include "core/math/math_defs.h"
+#include "core/templates/map.h"
#include "nav_utils.h"
#include <KdTree.h>
diff --git a/modules/gdnavigation/nav_region.cpp b/modules/gdnavigation/nav_region.cpp
index a07995bc11..c1690b2a4b 100644
--- a/modules/gdnavigation/nav_region.cpp
+++ b/modules/gdnavigation/nav_region.cpp
@@ -39,6 +39,9 @@
void NavRegion::set_map(NavMap *p_map) {
map = p_map;
polygons_dirty = true;
+ if (!map) {
+ connections.clear();
+ }
}
void NavRegion::set_layers(uint32_t p_layers) {
@@ -59,6 +62,25 @@ void NavRegion::set_mesh(Ref<NavigationMesh> p_mesh) {
polygons_dirty = true;
}
+int NavRegion::get_connections_count() const {
+ if (!map) {
+ return 0;
+ }
+ return connections.size();
+}
+
+Vector3 NavRegion::get_connection_pathway_start(int p_connection_id) const {
+ ERR_FAIL_COND_V(!map, Vector3());
+ ERR_FAIL_INDEX_V(p_connection_id, connections.size(), Vector3());
+ return connections[p_connection_id].pathway_start;
+}
+
+Vector3 NavRegion::get_connection_pathway_end(int p_connection_id) const {
+ ERR_FAIL_COND_V(!map, Vector3());
+ ERR_FAIL_INDEX_V(p_connection_id, connections.size(), Vector3());
+ return connections[p_connection_id].pathway_end;
+}
+
bool NavRegion::sync() {
bool something_changed = polygons_dirty /* || something_dirty? */;
diff --git a/modules/gdnavigation/nav_region.h b/modules/gdnavigation/nav_region.h
index fff7843fde..527b2500ac 100644
--- a/modules/gdnavigation/nav_region.h
+++ b/modules/gdnavigation/nav_region.h
@@ -49,6 +49,7 @@ class NavRegion : public NavRid {
Transform transform;
Ref<NavigationMesh> mesh;
uint32_t layers = 1;
+ Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@@ -80,6 +81,13 @@ public:
return mesh;
}
+ Vector<gd::Edge::Connection> &get_connections() {
+ return connections;
+ }
+ int get_connections_count() const;
+ Vector3 get_connection_pathway_start(int p_connection_id) const;
+ Vector3 get_connection_pathway_end(int p_connection_id) const;
+
std::vector<gd::Polygon> const &get_polygons() const {
return polygons;
}
diff --git a/modules/gdnavigation/nav_utils.h b/modules/gdnavigation/nav_utils.h
index d257a95ef1..35da391eea 100644
--- a/modules/gdnavigation/nav_utils.h
+++ b/modules/gdnavigation/nav_utils.h
@@ -81,11 +81,14 @@ struct Edge {
/// This edge ID
int this_edge = -1;
- /// Other Polygon
- Polygon *other_polygon = nullptr;
-
- /// The other `Polygon` at this edge id has this `Polygon`.
- int other_edge = -1;
+ /// The gateway in the edge, as, in some case, the whole edge might not be navigable.
+ struct Connection {
+ Polygon *polygon = nullptr;
+ int edge = -1;
+ Vector3 pathway_start;
+ Vector3 pathway_end;
+ };
+ Vector<Connection> connections;
};
struct Polygon {
@@ -104,21 +107,17 @@ struct Polygon {
Vector3 center;
};
-struct Connection {
- Polygon *A = nullptr;
- int A_edge = -1;
- Polygon *B = nullptr;
- int B_edge = -1;
-};
-
struct NavigationPoly {
uint32_t self_id = 0;
/// This poly.
const Polygon *poly;
- /// The previous navigation poly (id in the `navigation_poly` array).
- int prev_navigation_poly_id = -1;
- /// The edge id in this `Poly` to reach the `prev_navigation_poly_id`.
- uint32_t back_navigation_edge = 0;
+
+ /// Those 4 variables are used to travel the path backwards.
+ int back_navigation_poly_id = -1;
+ uint32_t back_navigation_edge = UINT32_MAX;
+ Vector3 back_navigation_edge_pathway_start;
+ Vector3 back_navigation_edge_pathway_end;
+
/// The entry location of this poly.
Vector3 entry;
/// The distance to the destination.
@@ -136,14 +135,6 @@ struct NavigationPoly {
}
};
-struct FreeEdge {
- bool is_free = false;
- Polygon *poly = nullptr;
- uint32_t edge_id = 0;
- Vector3 edge_center;
- Vector3 edge_dir;
- float edge_len_squared = 0.0;
-};
} // namespace gd
#endif // NAV_UTILS_H
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 06d628d23f..63ca34fc24 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1511,17 +1511,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.start_block();
// Evaluate the match expression.
- GDScriptCodeGenerator::Address value_local = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
- GDScriptCodeGenerator::Address value = _parse_expression(codegen, error, match->test);
+ GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
+ GDScriptCodeGenerator::Address value_expr = _parse_expression(codegen, error, match->test);
if (error) {
return error;
}
// Assign to local.
// TODO: This can be improved by passing the target to parse_expression().
- gen->write_assign(value_local, value);
+ gen->write_assign(value, value_expr);
- if (value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ if (value_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -2419,7 +2419,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
p_script->initializer->call(instance, nullptr, 0, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- //well, tough luck, not goinna do anything here
+ //well, tough luck, not gonna do anything here
}
}
#endif
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index c6c9a439df..7b37aa40a2 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -244,7 +244,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
bool completed = true;
// If the return value is a GDScriptFunctionState reference,
- // then the function did awaited again after resuming.
+ // then the function did await again after resuming.
if (ret.is_ref()) {
GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);
if (gdfs && gdfs->function == function) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 15cb3146ee..7f3dd6b2e5 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3018,7 +3018,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
// Avoid desync.
static_assert(sizeof(rules) / sizeof(rules[0]) == GDScriptTokenizer::Token::TK_MAX, "Amount of parse rules don't match the amount of token types.");
- // Let's assume this this never invalid, since nothing generates a TK_MAX.
+ // Let's assume this is never invalid, since nothing generates a TK_MAX.
return &rules[p_token_type];
}
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 315b8ee3b4..e432dfc891 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -898,6 +898,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
_advance();
_advance();
break;
+ } else {
+ // Not a multiline string termination, add consumed quote.
+ result += quote_char;
}
} else {
// Ended single-line string.
@@ -1169,7 +1172,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (pending_newline) {
pending_newline = false;
if (!multiline_mode) {
- // Don't return newline tokens on multine mode.
+ // Don't return newline tokens on multiline mode.
return last_newline;
}
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 4e098d7a6d..2216fcab2d 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -649,7 +649,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (scr_B) {
//if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this shoul return false.
+ //in other situation, this should return false.
if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index e90475a60e..93b709a613 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -85,7 +85,7 @@ public:
return;
}
- // TODO: Readd compiled GDScript on export.
+ // TODO: Re-add compiled GDScript on export.
return;
}
};
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index 1505a456d7..a4ee871eff 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -4,3 +4,27 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "EditorSceneImporterGLTF",
+ "GLTFAccessor",
+ "GLTFAnimation",
+ "GLTFBufferView",
+ "GLTFCamera",
+ "GLTFDocument",
+ "GLTFLight",
+ "GLTFMesh",
+ "GLTFNode",
+ "GLTFSkeleton",
+ "GLTFSkin",
+ "GLTFSpecGloss",
+ "GLTFState",
+ "GLTFTexture",
+ "PackedSceneGLTF",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/doc/classes/EditorSceneImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
index e717b30f73..e717b30f73 100644
--- a/doc/classes/EditorSceneImporterGLTF.xml
+++ b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
diff --git a/doc/classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml
index a1f596f7dd..a1f596f7dd 100644
--- a/doc/classes/GLTFAccessor.xml
+++ b/modules/gltf/doc_classes/GLTFAccessor.xml
diff --git a/doc/classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml
index 5c1fa02f11..5c1fa02f11 100644
--- a/doc/classes/GLTFAnimation.xml
+++ b/modules/gltf/doc_classes/GLTFAnimation.xml
diff --git a/doc/classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml
index edaad85e0a..edaad85e0a 100644
--- a/doc/classes/GLTFBufferView.xml
+++ b/modules/gltf/doc_classes/GLTFBufferView.xml
diff --git a/doc/classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml
index 0b95f2c802..0b95f2c802 100644
--- a/doc/classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
diff --git a/doc/classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 04c40dd752..04c40dd752 100644
--- a/doc/classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
diff --git a/doc/classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index bfeaf9a86e..bfeaf9a86e 100644
--- a/doc/classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
diff --git a/doc/classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index 55f79d2c55..55f79d2c55 100644
--- a/doc/classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
diff --git a/doc/classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 5b7d4fadec..5b7d4fadec 100644
--- a/doc/classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
diff --git a/doc/classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index 9680c27705..9680c27705 100644
--- a/doc/classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
diff --git a/doc/classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml
index 5a80c7097a..5a80c7097a 100644
--- a/doc/classes/GLTFSkin.xml
+++ b/modules/gltf/doc_classes/GLTFSkin.xml
diff --git a/doc/classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml
index 68cc7c845d..68cc7c845d 100644
--- a/doc/classes/GLTFSpecGloss.xml
+++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml
diff --git a/doc/classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 8255cd73d0..8255cd73d0 100644
--- a/doc/classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
diff --git a/doc/classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index be2210331f..ece5cf3fe3 100644
--- a/doc/classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="195773152">
+ <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="212600976">
</member>
</members>
<constants>
diff --git a/doc/classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml
index a04c6ef0b6..a04c6ef0b6 100644
--- a/doc/classes/PackedSceneGLTF.xml
+++ b/modules/gltf/doc_classes/PackedSceneGLTF.xml
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index 6ea722a216..35f44ca122 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -99,7 +99,9 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
Ref<GLTFDocument> gltf_document;
gltf_document.instance();
Error err = gltf_document->parse(r_state, p_path);
- *r_err = err;
+ if (r_err) {
+ *r_err = err;
+ }
ERR_FAIL_COND_V(err != Error::OK, nullptr);
Node3D *root = memnew(Node3D);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 0a4d4055b4..7ea0aa8ba2 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -63,7 +63,6 @@
#ifdef MODULE_GRIDMAP_ENABLED
#include "modules/gridmap/grid_map.h"
#endif // MODULE_GRIDMAP_ENABLED
-#include "modules/regex/regex.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
@@ -505,25 +504,11 @@ String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const Stri
return name;
}
-String GLTFDocument::_sanitize_bone_name(const String &name) {
- String p_name = name.camelcase_to_underscore(true);
-
- RegEx pattern_nocolon(":");
- p_name = pattern_nocolon.sub(p_name, "_", true);
-
- RegEx pattern_noslash("/");
- p_name = pattern_noslash.sub(p_name, "_", true);
-
- RegEx pattern_nospace(" +");
- p_name = pattern_nospace.sub(p_name, "_", true);
-
- RegEx pattern_multiple("_+");
- p_name = pattern_multiple.sub(p_name, "_", true);
-
- RegEx pattern_padded("0+(\\d+)");
- p_name = pattern_padded.sub(p_name, "$1", true);
-
- return p_name;
+String GLTFDocument::_sanitize_bone_name(const String &p_name) {
+ String name = p_name;
+ name = name.replace(":", "_");
+ name = name.replace("/", "_");
+ return name;
}
String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) {
@@ -5648,8 +5633,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->track_set_path(track_idx, node_path);
//first determine animation length
- const float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ const double increment = 1.0 / bake_fps;
+ double time = 0.0;
Vector3 base_pos;
Quat base_rot;
@@ -5739,8 +5724,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
} else {
// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
- const float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ const double increment = 1.0 / bake_fps;
+ double time = 0.0;
bool last = false;
while (true) {
_interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
diff --git a/modules/gltf/gltf_texture.h b/modules/gltf/gltf_texture.h
index e1d0407fb4..4659725502 100644
--- a/modules/gltf/gltf_texture.h
+++ b/modules/gltf/gltf_texture.h
@@ -38,7 +38,7 @@ class GLTFTexture : public Resource {
GDCLASS(GLTFTexture, Resource);
private:
- GLTFImageIndex src_image;
+ GLTFImageIndex src_image = 0;
protected:
static void _bind_methods();
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 25776b1f6d..9b6fa138e5 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -214,12 +214,12 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
The physics layers this GridMap detects collisions in. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
- <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
- The navigation layers the GridMap generates its navigable regions in.
- </member>
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
The assigned [MeshLibrary].
</member>
+ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
+ The navigation layers the GridMap generates its navigable regions in.
+ </member>
</members>
<signals>
<signal name="cell_size_changed">
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index d7597aa435..b39a6ecc2f 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -242,7 +242,7 @@ void StreamPeerMbedTLS::poll() {
return;
}
- // We could pass NULL as second parameter, but some behaviour sanitizers doesn't seem to like that.
+ // We could pass NULL as second parameter, but some behaviour sanitizers don't seem to like that.
// Passing a 1 byte buffer to workaround it.
uint8_t byte;
int ret = mbedtls_ssl_read(ssl_ctx->get_context(), &byte, 0);
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 25b110dc62..5140cfbbaf 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -153,8 +153,8 @@ void MobileVRInterface::set_position_from_sensors() {
last_magnetometer_data = magneto;
if (grav.length() < 0.1) {
- // not ideal but use our accelerometer, this will contain shakey shakey user behaviour
- // maybe look into some math but I'm guessing that if this isn't available, its because we lack the gyro sensor to actually work out
+ // not ideal but use our accelerometer, this will contain shaky user behaviour
+ // maybe look into some math but I'm guessing that if this isn't available, it's because we lack the gyro sensor to actually work out
// what a stable gravity vector is
grav = acc;
if (grav.length() > 0.1) {
@@ -181,8 +181,8 @@ void MobileVRInterface::set_position_from_sensors() {
tracking_state = XRInterface::XR_NORMAL_TRACKING;
};
- ///@TODO improve this, the magnetometer is very fidgity sometimes flipping the axis for no apparent reason (probably a bug on my part)
- // if you have a gyro + accelerometer that combo tends to be better then combining all three but without a gyro you need the magnetometer..
+ ///@TODO improve this, the magnetometer is very fidgety sometimes flipping the axis for no apparent reason (probably a bug on my part)
+ // if you have a gyro + accelerometer that combo tends to be better than combining all three but without a gyro you need the magnetometer..
if (has_magneto && has_grav && !has_gyro) {
// convert to quaternions, easier to smooth those out
Quat transform_quat(orientation);
@@ -372,7 +372,7 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons
if (initialized) {
float world_scale = xr_server->get_world_scale();
- // we don't need to check for the existence of our HMD, doesn't effect our values...
+ // we don't need to check for the existence of our HMD, doesn't affect our values...
// note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
if (p_eye == XRInterface::EYE_LEFT) {
transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
@@ -402,7 +402,7 @@ CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye,
CameraMatrix eye;
if (p_eye == XRInterface::EYE_MONO) {
- ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real cameras properties
+ ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real camera's properties
// which probably means implementing a specific class for iOS and Android. For now this is purely here as an example.
// Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface
// to position a stock standard Godot camera and have control over this.
diff --git a/modules/mono/SdkPackageVersions.props b/modules/mono/SdkPackageVersions.props
index 396443f30e..df3ebe581c 100644
--- a/modules/mono/SdkPackageVersions.props
+++ b/modules/mono/SdkPackageVersions.props
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
- <PackageVersion_Godot_NET_Sdk>4.0.0-dev4</PackageVersion_Godot_NET_Sdk>
- <PackageVersion_Godot_SourceGenerators>4.0.0-dev1</PackageVersion_Godot_SourceGenerators>
+ <PackageVersion_Godot_NET_Sdk>4.0.0-dev5</PackageVersion_Godot_NET_Sdk>
+ <PackageVersion_Godot_SourceGenerators>4.0.0-dev2</PackageVersion_Godot_SourceGenerators>
</PropertyGroup>
</Project>
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 4fca80fca0..43f57a7caa 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -328,7 +328,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin
String script_template = "using " BINDINGS_NAMESPACE ";\n"
"using System;\n"
"\n"
- "public class %CLASS% : %BASE%\n"
+ "public partial class %CLASS% : %BASE%\n"
"{\n"
" // Declare member variables here. Examples:\n"
" // private int a = 2;\n"
@@ -2018,22 +2018,20 @@ void CSharpInstance::connect_event_signals() {
// TODO: Use pooling for ManagedCallable instances.
auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
- owner->connect(signal_name, Callable(event_signal_callable));
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
}
}
void CSharpInstance::disconnect_event_signals() {
- for (const Map<StringName, CSharpScript::EventSignal>::Element *E = script->event_signals.front(); E; E = E->next()) {
- const CSharpScript::EventSignal &event_signal = E->value();
-
- StringName signal_name = event_signal.field->get_name();
-
- // TODO: It would be great if we could store this EventSignalCallable on the stack.
- // The problem is that Callable memdeletes it when it's destructed...
- auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
-
- owner->disconnect(signal_name, Callable(event_signal_callable));
+ for (const List<Callable>::Element *E = connected_event_signals.front(); E; E = E->next()) {
+ const Callable &callable = E->get();
+ auto event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom());
+ owner->disconnect(event_signal_callable->get_signal(), callable);
}
+
+ connected_event_signals.clear();
}
void CSharpInstance::refcount_incremented() {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 40f7ed4552..dd93a86d7a 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -271,6 +271,8 @@ class CSharpInstance : public ScriptInstance {
Ref<CSharpScript> script;
MonoGCHandleData gchandle;
+ List<Callable> connected_event_signals;
+
bool _reference_owner_unsafe();
/*
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
index ef8add0ba8..4e9e7184da 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -23,11 +23,12 @@
<ItemGroup>
<!-- Package Sdk\Sdk.props and Sdk\Sdk.targets file -->
- <None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" Visible="false" />
- <None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" Visible="false" />
+ <None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" />
+ <None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" />
<!-- SdkPackageVersions.props -->
-
- <None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk" Visible="false" />
+ <None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk">
+ <Link>Sdk\SdkPackageVersions.props</Link>
+ </None>
</ItemGroup>
<Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index c3e74822d5..e16f72f43a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -82,5 +82,8 @@ namespace Godot.SourceGenerators
public static string FullQualifiedName(this INamedTypeSymbol symbol)
=> symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index 150e59e414..a51728e221 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -69,7 +69,7 @@ namespace Godot.SourceGenerators
IEnumerable<ClassDeclarationSyntax> classDeclarations
)
{
- var attributesBuilder = new StringBuilder();
+ var attributes = new StringBuilder();
// Remember syntax trees for which we already added an attribute, to prevent unnecessary duplicates.
var attributedTrees = new List<SyntaxTree>();
@@ -81,28 +81,54 @@ namespace Godot.SourceGenerators
attributedTrees.Add(cds.SyntaxTree);
- if (attributesBuilder.Length != 0)
- attributesBuilder.Append("\n ");
+ if (attributes.Length != 0)
+ attributes.Append("\n");
- attributesBuilder.Append(@"[ScriptPathAttribute(""res://");
- attributesBuilder.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir));
- attributesBuilder.Append(@""")]");
+ attributes.Append(@"[ScriptPathAttribute(""res://");
+ attributes.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir));
+ attributes.Append(@""")]");
}
- string classNs = symbol.ContainingNamespace.Name;
string className = symbol.Name;
- var source = $@"using Godot;
-namespace {classNs}
-{{
- {attributesBuilder}
- partial class {className}
- {{
- }}
-}}
-";
- context.AddSource(classNs + "." + className + "_ScriptPath_Generated",
- SourceText.From(source, Encoding.UTF8));
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ string uniqueName = hasNamespace ?
+ classNs + "." + className + "_ScriptPath_Generated" :
+ className + "_ScriptPath_Generated";
+
+ var source = new StringBuilder();
+
+ // using Godot;
+ // namespace {classNs} {
+ // {attributesBuilder}
+ // partial class {className} { }
+ // }
+
+ source.Append("using Godot;\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ source.Append(attributes);
+ source.Append("\n partial class ");
+ source.Append(className);
+ source.Append("\n{\n}\n");
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueName, SourceText.From(source.ToString(), Encoding.UTF8));
}
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index b1875aec3f..b48e5df9eb 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -3631,11 +3631,44 @@ void BindingsGenerator::_initialize() {
initialized = true;
}
+static String generate_all_glue_option = "--generate-mono-glue";
+static String generate_cs_glue_option = "--generate-mono-cs-glue";
+static String generate_cpp_glue_option = "--generate-mono-cpp-glue";
+
+static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, String cpp_dir_path) {
+ BindingsGenerator bindings_generator;
+ bindings_generator.set_log_print_enabled(true);
+
+ if (!bindings_generator.is_initialized()) {
+ ERR_PRINT("Failed to initialize the bindings generator");
+ return;
+ }
+
+ if (glue_dir_path.length()) {
+ if (bindings_generator.generate_glue(glue_dir_path) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
+ }
+
+ if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
+ }
+ }
+
+ if (cs_dir_path.length()) {
+ if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
+ ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
+ }
+ }
+
+ if (cpp_dir_path.length()) {
+ if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
+ ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
+ }
+ }
+}
+
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
const int NUM_OPTIONS = 2;
- String generate_all_glue_option = "--generate-mono-glue";
- String generate_cs_glue_option = "--generate-mono-cs-glue";
- String generate_cpp_glue_option = "--generate-mono-cpp-glue";
String glue_dir_path;
String cs_dir_path;
@@ -3643,6 +3676,8 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
int options_left = NUM_OPTIONS;
+ bool exit_godot = false;
+
const List<String>::Element *elem = p_cmdline_args.front();
while (elem && options_left) {
@@ -3654,6 +3689,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue').");
+ exit_godot = true;
}
--options_left;
@@ -3665,6 +3701,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_cs_glue_option + ": No output directory specified.");
+ exit_godot = true;
}
--options_left;
@@ -3676,6 +3713,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_cpp_glue_option + ": No output directory specified.");
+ exit_godot = true;
}
--options_left;
@@ -3685,37 +3723,11 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
}
if (glue_dir_path.length() || cs_dir_path.length() || cpp_dir_path.length()) {
- BindingsGenerator bindings_generator;
- bindings_generator.set_log_print_enabled(true);
-
- if (!bindings_generator.initialized) {
- ERR_PRINT("Failed to initialize the bindings generator");
- Main::cleanup(true);
- ::exit(0);
- }
-
- if (glue_dir_path.length()) {
- if (bindings_generator.generate_glue(glue_dir_path) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
- }
-
- if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
- }
- }
-
- if (cs_dir_path.length()) {
- if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
- ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
- }
- }
-
- if (cpp_dir_path.length()) {
- if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
- ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
- }
- }
+ handle_cmdline_options(glue_dir_path, cs_dir_path, cpp_dir_path);
+ exit_godot = true;
+ }
+ if (exit_godot) {
// Exit once done
Main::cleanup(true);
::exit(0);
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index cba29d63cd..c65353dfd1 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -415,8 +415,7 @@ GD_PINVOKE_EXPORT int32_t monodroid_get_system_property(const char *p_name, char
if (r_value) {
if (len >= 0) {
*r_value = (char *)malloc(len + 1);
- if (!*r_value)
- return -1;
+ ERR_FAIL_NULL_V_MSG(*r_value, -1, "Out of memory.");
memcpy(*r_value, prop_value_str, len);
(*r_value)[len] = '\0';
} else {
@@ -637,6 +636,7 @@ GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array)
if (dns_servers_count > 0) {
size_t ret_size = sizeof(char *) * (size_t)dns_servers_count;
*r_dns_servers_array = malloc(ret_size); // freed by the BCL
+ ERR_FAIL_NULL_V_MSG(*r_dns_servers_array, -1, "Out of memory.");
memcpy(*r_dns_servers_array, dns_servers, ret_size);
}
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index b4067d41c2..e7863f88a3 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -83,8 +83,8 @@ if env["builtin_harfbuzz"]:
"src/hb-ot-shape-complex-indic.cc",
"src/hb-ot-shape-complex-khmer.cc",
"src/hb-ot-shape-complex-myanmar.cc",
+ "src/hb-ot-shape-complex-syllabic.cc",
"src/hb-ot-shape-complex-thai.cc",
- "src/hb-ot-shape-complex-use-table.cc",
"src/hb-ot-shape-complex-use.cc",
"src/hb-ot-shape-complex-vowel-constraints.cc",
"src/hb-ot-shape-fallback.cc",
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index b60b9ddaec..2521e68dda 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -129,7 +129,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
fds->underline_position = (-FT_MulFix(fds->face->underline_position, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
fds->underline_thickness = (FT_MulFix(fds->face->underline_thickness, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
- //Load os2 TTF pable
+ //Load os2 TTF table
fds->os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fds->face, FT_SFNT_OS2);
fds->hb_handle = hb_ft_font_create(fds->face, nullptr);
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 2e3c2d1cab..43b8f18101 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -166,7 +166,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
#ifdef ICU_STATIC_DATA
if (icu_data == nullptr) {
UErrorCode err = U_ZERO_ERROR;
- u_init(&err); // Do not check for errors, since we only load part the of data.
+ u_init(&err); // Do not check for errors, since we only load part of the data.
icu_data = (uint8_t *)&U_ICUDATA_ENTRY_POINT;
}
#else
@@ -244,7 +244,7 @@ struct FeatureInfo {
};
static FeatureInfo feature_set[] = {
- // Registred OpenType feature tags.
+ // Registered OpenType feature tags.
{ HB_TAG('a', 'a', 'l', 't'), "access_all_alternates" },
{ HB_TAG('a', 'b', 'v', 'f'), "above_base_forms" },
{ HB_TAG('a', 'b', 'v', 'm'), "above_base_mark_positioning" },
@@ -484,7 +484,7 @@ static FeatureInfo feature_set[] = {
{ HB_TAG('v', 'r', 't', '2'), "vertical_alternates_and_rotation" },
{ HB_TAG('v', 'r', 't', 'r'), "vertical_alternates_for_rotation" },
{ HB_TAG('z', 'e', 'r', 'o'), "slashed_zero" },
- // Registred OpenType variation tags.
+ // Registered OpenType variation tags.
{ HB_TAG('i', 't', 'a', 'l'), "italic" },
{ HB_TAG('o', 'p', 's', 'z'), "optical_size" },
{ HB_TAG('s', 'l', 'n', 't'), "slant" },
@@ -1660,7 +1660,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
}
if (sd->line_breaks_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
const UChar *data = sd->utf16.ptr();
@@ -1845,7 +1845,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
}
if (sd->justification_ops_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
const UChar *data = sd->utf16.ptr();
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 60ab14738a..f46f96d30d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1091,7 +1091,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
}
if (sd->line_breaks_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
int sd_size = sd->glyphs.size();
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index bc0b215be3..b2fed0cb23 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -12,18 +12,19 @@ thirdparty_obj = []
if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
+ "igd_desc_parse.c",
"miniupnpc.c",
- "upnpcommands.c",
+ "minixml.c",
+ "minisoap.c",
+ "minissdpc.c",
"miniwget.c",
+ "upnpcommands.c",
"upnpdev.c",
- "igd_desc_parse.c",
- "minissdpc.c",
- "minisoap.c",
- "minixml.c",
+ "upnpreplyparse.c",
"connecthostport.c",
- "receivedata.c",
"portlistingparse.c",
- "upnpreplyparse.c",
+ "receivedata.c",
+ "addr_is_reserved.c",
]
thirdparty_sources = [thirdparty_dir + "miniupnpc/" + file for file in thirdparty_sources]
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index cff13251ce..8e4e833d45 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -52,10 +52,12 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) {
int error = 0;
struct UPNPDev *devlist;
+ CharString cs = discover_multicast_if.utf8();
+ const char *m_if = cs.length() ? cs.get_data() : nullptr;
if (is_common_device(device_filter)) {
- devlist = upnpDiscover(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
} else {
- devlist = upnpDiscoverAll(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
}
if (error != UPNPDISCOVER_SUCCESS) {
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 2517b17168..e91ae46a57 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -1369,7 +1369,7 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
// Is a default value (unassigned input port).
input_args[i] = &default_values[index];
} else {
- // Rregular temporary in stack.
+ // Regular temporary in stack.
input_args[i] = &variant_stack[index];
}
}
@@ -1391,7 +1391,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
ERR_FAIL_COND_V(!F, Variant());
Function *f = &F->get();
- // This call goes separate, so it can e yielded and suspended.
+ // This call goes separate, so it can be yielded and suspended.
Variant *variant_stack = (Variant *)p_stack;
bool *sequence_bits = (bool *)(variant_stack + f->max_stack);
const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index fcd55b3049..3b2cd50544 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -3958,7 +3958,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (start_node == -1) {
// If we still don't have a start node then,
// run through the nodes and select the first tree node,
- // ie node without any input sequence but output sequence.
+ // i.e. node without any input sequence but output sequence.
for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {
if (!nodes_to.has(E->get())) {
start_node = E->get();
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index f673cbb06d..cb4230bea9 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -1054,7 +1054,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
}
}
- /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+ /* Reduce the set of expressions and place them in an operator tree, respecting precedence */
while (expression.size() > 1) {
int next_op = -1;
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index e2a8323509..e977f9c96b 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -800,7 +800,7 @@ public:
}
if (!ResourceCache::has(script)) {
- //if the script is not in use by anyone, we can safely assume whathever we got is not casting to it.
+ //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it.
return 1;
}
Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index b5aacb0506..9310b86627 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -547,7 +547,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
@@ -1292,7 +1292,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
@@ -1970,7 +1970,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index 25fabd7b87..52fe659983 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -425,7 +425,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 011cb86535..758ed66c80 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -53,7 +53,7 @@ int WebSocketMultiplayerPeer::_gen_unique_id() const {
(uint32_t)((uint64_t)this), hash); //rely on aslr heap
hash = hash_djb2_one_32(
(uint32_t)((uint64_t)&hash), hash); //rely on aslr stack
- hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion
+ hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negative id is used for exclusion
}
return hash;
@@ -186,7 +186,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
int32_t id = E->key();
if (p_peer_id == id) {
- continue; // Skip the newwly added peer (already confirmed)
+ continue; // Skip the newly added peer (already confirmed)
}
// Send new peer to others
@@ -314,7 +314,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
_peer_map.erase(id);
emit_signal("peer_disconnected", id);
break;
- case SYS_ID: // Helo, server assigned ID
+ case SYS_ID: // Hello, server assigned ID
_peer_id = id;
break;
default:
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index fb4df10904..e1f9521a48 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -161,8 +161,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
const xatlas::Mesh &output = atlas->meshes[0];
*r_vertices = (int *)malloc(sizeof(int) * output.vertexCount);
+ ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory.");
*r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2);
+ ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory.");
*r_indices = (int *)malloc(sizeof(int) * output.indexCount);
+ ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory.");
float max_x = 0.0;
float max_y = 0.0;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 5f0fcc9b77..996b6dcf41 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -197,12 +197,11 @@ def configure(env):
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(LINKFLAGS=["-O2"])
env.Append(CCFLAGS=["-O2", "-fomit-frame-pointer"])
- env.Append(CPPDEFINES=["NDEBUG"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os"])
- env.Append(CPPDEFINES=["NDEBUG"])
env.Append(LINKFLAGS=["-Os"])
+ env.Append(CPPDEFINES=["NDEBUG"])
if can_vectorize:
env.Append(CCFLAGS=["-ftree-vectorize"])
if env["target"] == "release_debug":
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index 165d5da3ae..e288c16777 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -114,6 +114,9 @@ uint8_t FileAccessAndroid::get_8() const {
}
int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
off_t r = AAsset_read(a, p_dst, p_length);
if (pos + p_length > len) {
diff --git a/platform/android/java/app/assets/.gitignore b/platform/android/java/app/assets/.gitignore
new file mode 100644
index 0000000000..d6b7ef32c8
--- /dev/null
+++ b/platform/android/java/app/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 934c4bf441..f103f22db2 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -77,7 +77,7 @@ android {
defaultConfig {
// The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
aaptOptions {
- ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
+ ignoreAssetsPattern "!.svn:!.git:!.gitignore:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
ndk {
@@ -106,8 +106,10 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
+ // 'doNotStrip' is enabled for development within Android Studio
+ if (shouldNotStrip()) {
+ doNotStrip '**/*.so'
+ }
}
signingConfigs {
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 585e517631..c0ae4007d2 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -209,10 +209,19 @@ ext.getReleaseKeyAlias = { ->
return keyAlias
}
+ext.isAndroidStudio = { ->
+ def sysProps = System.getProperties()
+ return sysProps != null && sysProps['idea.platform.prefix'] != null
+}
+
ext.shouldZipAlign = { ->
String zipAlignFlag = project.hasProperty("perform_zipalign") ? project.property("perform_zipalign") : ""
if (zipAlignFlag == null || zipAlignFlag.isEmpty()) {
- zipAlignFlag = "false"
+ if (isAndroidStudio()) {
+ zipAlignFlag = "true"
+ } else {
+ zipAlignFlag = "false"
+ }
}
return Boolean.parseBoolean(zipAlignFlag)
}
@@ -220,7 +229,15 @@ ext.shouldZipAlign = { ->
ext.shouldSign = { ->
String signFlag = project.hasProperty("perform_signing") ? project.property("perform_signing") : ""
if (signFlag == null || signFlag.isEmpty()) {
- signFlag = "false"
+ if (isAndroidStudio()) {
+ signFlag = "true"
+ } else {
+ signFlag = "false"
+ }
}
return Boolean.parseBoolean(signFlag)
}
+
+ext.shouldNotStrip = { ->
+ return isAndroidStudio()
+}
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 6fc9a11a08..663ba73d40 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -36,8 +36,10 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
+ // 'doNotStrip' is enabled for development within Android Studio
+ if (shouldNotStrip()) {
+ doNotStrip '**/*.so'
+ }
}
sourceSets {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index 4e67402c63..ec2ace4821 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -34,6 +34,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
+import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
@@ -44,7 +45,7 @@ import androidx.fragment.app.FragmentActivity;
* It's also a reference implementation for how to setup and use the {@link Godot} fragment
* within an Android app.
*/
-public abstract class FullScreenGodotApp extends FragmentActivity {
+public abstract class FullScreenGodotApp extends FragmentActivity implements GodotHost {
@Nullable
private Godot godotFragment;
@@ -64,6 +65,28 @@ public abstract class FullScreenGodotApp extends FragmentActivity {
public void onNewIntent(Intent intent) {
if (godotFragment != null) {
godotFragment.onNewIntent(intent);
+ } else {
+ super.onNewIntent(intent);
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (godotFragment != null) {
+ godotFragment.onActivityResult(requestCode, resultCode, data);
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ if (godotFragment != null) {
+ godotFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 0891904dff..0c16214c8a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -103,6 +103,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -131,6 +132,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
private boolean activityResumed;
private int mState;
+ private GodotHost godotHost;
private GodotPluginRegistry pluginRegistry;
static private Intent mCurrentIntent;
@@ -178,7 +180,25 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public ResultCallback result_callback;
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof GodotHost) {
+ godotHost = (GodotHost)getParentFragment();
+ } else if (getActivity() instanceof GodotHost) {
+ godotHost = (GodotHost)getActivity();
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ godotHost = null;
+ }
+
+ @CallSuper
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
if (result_callback != null) {
result_callback.callback(requestCode, resultCode, data);
result_callback = null;
@@ -189,8 +209,10 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
}
+ @CallSuper
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainRequestPermissionsResult(requestCode, permissions, grantResults);
}
@@ -201,6 +223,20 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
};
/**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ @CallSuper
+ protected void onGodotSetupCompleted() {
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGodotSetupCompleted();
+ }
+
+ if (godotHost != null) {
+ godotHost.onGodotSetupCompleted();
+ }
+ }
+
+ /**
* Invoked on the render thread when the Godot main loop has started.
*/
@CallSuper
@@ -208,6 +244,10 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGodotMainLoopStarted();
}
+
+ if (godotHost != null) {
+ godotHost.onGodotMainLoopStarted();
+ }
}
/**
@@ -228,7 +268,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
GodotLib.setup(command_line);
- final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name");
+ final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name");
if (videoDriver.equals("Vulkan")) {
mRenderView = new GodotVulkanRenderView(activity, this);
} else {
@@ -301,7 +341,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(durationMs, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
- //deprecated in API 26
+ // deprecated in API 26
v.vibrate(durationMs);
}
}
@@ -356,6 +396,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
@CallSuper
protected String[] getCommandLine() {
+ String[] original = parseCommandLine();
+ String[] updated;
+ List<String> hostCommandLine = godotHost != null ? godotHost.getCommandLine() : null;
+ if (hostCommandLine == null || hostCommandLine.isEmpty()) {
+ updated = original;
+ } else {
+ updated = Arrays.copyOf(original, original.length + hostCommandLine.size());
+ for (int i = 0; i < hostCommandLine.size(); i++) {
+ updated[original.length + i] = hostCommandLine.get(i);
+ }
+ }
+ return updated;
+ }
+
+ private String[] parseCommandLine() {
InputStream is;
try {
is = getActivity().getAssets().open("_cl_");
@@ -473,7 +528,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
mClipboard = (ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this);
- //check for apk expansion API
+ // check for apk expansion API
boolean md5mismatch = false;
command_line = getCommandLine();
String main_pack_md5 = null;
@@ -529,9 +584,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
command_line = new_args.toArray(new String[new_args.size()]);
}
if (use_apk_expansion && main_pack_md5 != null && main_pack_key != null) {
- //check that environment is ok!
+ // check that environment is ok!
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- //show popup and die
+ // show popup and die
}
// Build the full path to the app's expansion files
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
new file mode 100644
index 0000000000..317fd13535
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* GodotHost.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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. */
+/*************************************************************************/
+
+package org.godotengine.godot;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Denotate a component (e.g: Activity, Fragment) that hosts the {@link Godot} fragment.
+ */
+public interface GodotHost {
+ /**
+ * Provides a set of command line parameters to setup the engine.
+ */
+ default List<String> getCommandLine() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ default void onGodotSetupCompleted() {}
+
+ /**
+ * Invoked on the render thread when the Godot main loop has started.
+ */
+ default void onGodotMainLoopStarted() {}
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index 993f0e9127..6c8a3d4219 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -47,6 +47,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -109,31 +110,9 @@ public abstract class GodotPlugin {
* This method is invoked on the render thread.
*/
public final void onRegisterPluginWithGodotNative() {
- registeredSignals.putAll(registerPluginWithGodotNative(this, new GodotPluginInfoProvider() {
- @NonNull
- @Override
- public String getPluginName() {
- return GodotPlugin.this.getPluginName();
- }
-
- @NonNull
- @Override
- public List<String> getPluginMethods() {
- return GodotPlugin.this.getPluginMethods();
- }
-
- @NonNull
- @Override
- public Set<SignalInfo> getPluginSignals() {
- return GodotPlugin.this.getPluginSignals();
- }
-
- @NonNull
- @Override
- public Set<String> getPluginGDNativeLibrariesPaths() {
- return GodotPlugin.this.getPluginGDNativeLibrariesPaths();
- }
- }));
+ registeredSignals.putAll(
+ registerPluginWithGodotNative(this, getPluginName(), getPluginMethods(), getPluginSignals(),
+ getPluginGDNativeLibrariesPaths()));
}
/**
@@ -141,23 +120,41 @@ public abstract class GodotPlugin {
*
* This method must be invoked on the render thread.
*/
- public static Map<String, SignalInfo> registerPluginWithGodotNative(Object pluginObject, GodotPluginInfoProvider pluginInfoProvider) {
- nativeRegisterSingleton(pluginInfoProvider.getPluginName(), pluginObject);
+ public static void registerPluginWithGodotNative(Object pluginObject,
+ GodotPluginInfoProvider pluginInfoProvider) {
+ registerPluginWithGodotNative(pluginObject, pluginInfoProvider.getPluginName(),
+ Collections.emptyList(), pluginInfoProvider.getPluginSignals(),
+ pluginInfoProvider.getPluginGDNativeLibrariesPaths());
+
+ // Notify that registration is complete.
+ pluginInfoProvider.onPluginRegistered();
+ }
+ private static Map<String, SignalInfo> registerPluginWithGodotNative(Object pluginObject,
+ String pluginName, List<String> pluginMethods, Set<SignalInfo> pluginSignals,
+ Set<String> pluginGDNativeLibrariesPaths) {
+ nativeRegisterSingleton(pluginName, pluginObject);
+
+ Set<Method> filteredMethods = new HashSet<>();
Class clazz = pluginObject.getClass();
+
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
- boolean found = false;
-
- for (String s : pluginInfoProvider.getPluginMethods()) {
- if (s.equals(method.getName())) {
- found = true;
- break;
+ // Check if the method is annotated with {@link UsedByGodot}.
+ if (method.getAnnotation(UsedByGodot.class) != null) {
+ filteredMethods.add(method);
+ } else {
+ // For backward compatibility, process the methods from the given <pluginMethods> argument.
+ for (String methodName : pluginMethods) {
+ if (methodName.equals(method.getName())) {
+ filteredMethods.add(method);
+ break;
+ }
}
}
- if (!found)
- continue;
+ }
+ for (Method method : filteredMethods) {
List<String> ptr = new ArrayList<>();
Class[] paramTypes = method.getParameterTypes();
@@ -168,21 +165,20 @@ public abstract class GodotPlugin {
String[] pt = new String[ptr.size()];
ptr.toArray(pt);
- nativeRegisterMethod(pluginInfoProvider.getPluginName(), method.getName(), method.getReturnType().getName(), pt);
+ nativeRegisterMethod(pluginName, method.getName(), method.getReturnType().getName(), pt);
}
// Register the signals for this plugin.
Map<String, SignalInfo> registeredSignals = new HashMap<>();
- for (SignalInfo signalInfo : pluginInfoProvider.getPluginSignals()) {
+ for (SignalInfo signalInfo : pluginSignals) {
String signalName = signalInfo.getName();
- nativeRegisterSignal(pluginInfoProvider.getPluginName(), signalName, signalInfo.getParamTypesNames());
+ nativeRegisterSignal(pluginName, signalName, signalInfo.getParamTypesNames());
registeredSignals.put(signalName, signalInfo);
}
// Get the list of gdnative libraries to register.
- Set<String> gdnativeLibrariesPaths = pluginInfoProvider.getPluginGDNativeLibrariesPaths();
- if (!gdnativeLibrariesPaths.isEmpty()) {
- nativeRegisterGDNativeLibraries(gdnativeLibrariesPaths.toArray(new String[0]));
+ if (!pluginGDNativeLibrariesPaths.isEmpty()) {
+ nativeRegisterGDNativeLibraries(pluginGDNativeLibrariesPaths.toArray(new String[0]));
}
return registeredSignals;
@@ -236,6 +232,11 @@ public abstract class GodotPlugin {
public boolean onMainBackPressed() { return false; }
/**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ public void onGodotSetupCompleted() {}
+
+ /**
* Invoked on the render thread when the Godot main loop has started.
*/
public void onGodotMainLoopStarted() {}
@@ -282,8 +283,11 @@ public abstract class GodotPlugin {
/**
* Returns the list of methods to be exposed to Godot.
+ *
+ * @deprecated Used the {@link UsedByGodot} annotation instead.
*/
@NonNull
+ @Deprecated
public List<String> getPluginMethods() {
return Collections.emptyList();
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java
index c3084b036e..09366384c2 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java
@@ -32,7 +32,7 @@ package org.godotengine.godot.plugin;
import androidx.annotation.NonNull;
-import java.util.List;
+import java.util.Collections;
import java.util.Set;
/**
@@ -46,16 +46,12 @@ public interface GodotPluginInfoProvider {
String getPluginName();
/**
- * Returns the list of methods to be exposed to Godot.
- */
- @NonNull
- List<String> getPluginMethods();
-
- /**
* Returns the list of signals to be exposed to Godot.
*/
@NonNull
- Set<SignalInfo> getPluginSignals();
+ default Set<SignalInfo> getPluginSignals() {
+ return Collections.emptySet();
+ }
/**
* Returns the paths for the plugin's gdnative libraries (if any).
@@ -63,5 +59,14 @@ public interface GodotPluginInfoProvider {
* The paths must be relative to the 'assets' directory and point to a '*.gdnlib' file.
*/
@NonNull
- Set<String> getPluginGDNativeLibrariesPaths();
+ default Set<String> getPluginGDNativeLibrariesPaths() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * This is invoked on the render thread when the plugin described by this instance has been
+ * registered.
+ */
+ default void onPluginRegistered() {
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java
new file mode 100644
index 0000000000..04c091d944
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* UsedByGodot.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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. */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate a method is being invoked from the Godot game logic.
+ *
+ * At runtime, annotated plugin methods are detected and automatically registered.
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UsedByGodot {}
diff --git a/platform/android/java/nativeSrcsConfigs/README.md b/platform/android/java/nativeSrcsConfigs/README.md
index e48505ccda..9d884415cc 100644
--- a/platform/android/java/nativeSrcsConfigs/README.md
+++ b/platform/android/java/nativeSrcsConfigs/README.md
@@ -1,4 +1,4 @@
## Native sources configs
-This is a non functional Android library used to provide Android Studio editor support to the Godot project native files.
+This is a non-functional Android library used to provide Android Studio editor support to the Godot project native files.
Nothing else should be added to this library.
diff --git a/platform/android/java/nativeSrcsConfigs/build.gradle b/platform/android/java/nativeSrcsConfigs/build.gradle
index 66077060ea..158bb2b98e 100644
--- a/platform/android/java/nativeSrcsConfigs/build.gradle
+++ b/platform/android/java/nativeSrcsConfigs/build.gradle
@@ -20,9 +20,6 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
-
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
}
sourceSets {
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index ab03599dc3..f49b0e843a 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -38,6 +38,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
return false;
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
MethodInfo *method = nullptr;
for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) {
@@ -965,6 +966,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
return class_cache[p_class];
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, Ref<JavaClass>());
jclass bclass = env->FindClass(p_class.utf8().get_data());
ERR_FAIL_COND_V(!bclass, Ref<JavaClass>());
@@ -1149,6 +1151,7 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
singleton = this;
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jclass activityClass = env->FindClass("android/app/Activity");
jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 41201db32b..ec3b6f8ac0 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -73,6 +73,7 @@ jobject GodotIOJavaWrapper::get_instance() {
Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
if (_open_URI) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, ERR_UNAVAILABLE);
jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
} else {
@@ -83,6 +84,7 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
String GodotIOJavaWrapper::get_user_data_dir() {
if (_get_data_dir) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
return jstring_to_string(s, env);
} else {
@@ -93,6 +95,7 @@ String GodotIOJavaWrapper::get_user_data_dir() {
String GodotIOJavaWrapper::get_locale() {
if (_get_locale) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale);
return jstring_to_string(s, env);
} else {
@@ -103,6 +106,7 @@ String GodotIOJavaWrapper::get_locale() {
String GodotIOJavaWrapper::get_model() {
if (_get_model) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model);
return jstring_to_string(s, env);
} else {
@@ -113,6 +117,7 @@ String GodotIOJavaWrapper::get_model() {
int GodotIOJavaWrapper::get_screen_dpi() {
if (_get_screen_DPI) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 160);
return env->CallIntMethod(godot_io_instance, _get_screen_DPI);
} else {
return 160;
@@ -122,6 +127,7 @@ int GodotIOJavaWrapper::get_screen_dpi() {
void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
if (_screen_get_usable_rect) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _screen_get_usable_rect);
ERR_FAIL_COND(env->GetArrayLength(returnArray) != 4);
jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE);
@@ -135,6 +141,7 @@ void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
String GodotIOJavaWrapper::get_unique_id() {
if (_get_unique_id) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_id);
return jstring_to_string(s, env);
} else {
@@ -149,6 +156,7 @@ bool GodotIOJavaWrapper::has_vk() {
void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
}
@@ -157,6 +165,7 @@ void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int
void GodotIOJavaWrapper::hide_vk() {
if (_hide_keyboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(godot_io_instance, _hide_keyboard);
}
}
@@ -164,6 +173,7 @@ void GodotIOJavaWrapper::hide_vk() {
void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
if (_set_screen_orientation) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
}
}
@@ -171,6 +181,7 @@ void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
int GodotIOJavaWrapper::get_screen_orientation() {
if (_get_screen_orientation) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 0);
return env->CallIntMethod(godot_io_instance, _get_screen_orientation);
} else {
return 0;
@@ -180,6 +191,7 @@ int GodotIOJavaWrapper::get_screen_orientation() {
String GodotIOJavaWrapper::get_system_dir(int p_dir) {
if (_get_system_dir) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String("."));
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
return jstring_to_string(s, env);
} else {
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index bb22162879..0c342dc280 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -127,9 +127,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
- cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *));
+ cmdline = (const char **)memalloc((cmdlen + 1) * sizeof(const char *));
+ ERR_FAIL_NULL_MSG(cmdline, "Out of memory.");
cmdline[cmdlen] = nullptr;
- j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring));
+ j_cmdline = (jstring *)memalloc(cmdlen * sizeof(jstring));
+ ERR_FAIL_NULL_MSG(j_cmdline, "Out of memory.");
for (int i = 0; i < cmdlen; i++) {
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
@@ -147,13 +149,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
for (int i = 0; i < cmdlen; ++i) {
env->ReleaseStringUTFChars(j_cmdline[i], cmdline[i]);
}
- free(j_cmdline);
+ memfree(j_cmdline);
}
- free(cmdline);
+ memfree(cmdline);
}
if (err != OK) {
- return; //should exit instead and print the error
+ return; // should exit instead and print the error
}
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
@@ -215,9 +217,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
if (step == 1) {
if (!Main::start()) {
- return; //should exit instead and print the error
+ return; // should exit instead and print the error
}
+ godot_java->on_godot_setup_completed(env);
os_android->main_loop_begin();
godot_java->on_godot_main_loop_started(env);
++step;
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 5b638300ef..6b5e44f371 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -34,6 +34,7 @@
GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
_godot_view = env->NewGlobalRef(godot_view);
@@ -48,6 +49,8 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
void GodotJavaViewWrapper::request_pointer_capture() {
if (_request_pointer_capture != 0) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(_godot_view, _request_pointer_capture);
}
}
@@ -55,12 +58,16 @@ void GodotJavaViewWrapper::request_pointer_capture() {
void GodotJavaViewWrapper::release_pointer_capture() {
if (_request_pointer_capture != 0) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(_godot_view, _release_pointer_capture);
}
}
GodotJavaViewWrapper::~GodotJavaViewWrapper() {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->DeleteGlobalRef(_godot_view);
env->DeleteGlobalRef(_cls);
}
diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h
index 548c278292..bfb4369fb8 100644
--- a/platform/android/java_godot_view_wrapper.h
+++ b/platform/android/java_godot_view_wrapper.h
@@ -34,6 +34,8 @@
#include <android/log.h>
#include <jni.h>
+#include "string_android.h"
+
// Class that makes functions in java/src/org/godotengine/godot/GodotView.java callable from C++
class GodotJavaViewWrapper {
private:
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 759980373a..bfd93345f3 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -74,6 +74,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_is_activity_resumed = p_env->GetMethodID(godot_class, "isActivityResumed", "()Z");
_vibrate = p_env->GetMethodID(godot_class, "vibrate", "(I)V");
_get_input_fallback_mapping = p_env->GetMethodID(godot_class, "getInputFallbackMapping", "()Ljava/lang/String;");
+ _on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
// get some Activity method pointers...
@@ -93,6 +94,8 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND_V(p_env == nullptr, nullptr);
+
jfieldID fid = p_env->GetStaticFieldID(godot_class, p_name, p_class);
return p_env->GetStaticObjectField(godot_class, fid);
} else {
@@ -103,6 +106,8 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl
jobject GodotJavaWrapper::get_class_loader() {
if (_get_class_loader) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
return env->CallObjectMethod(activity, _get_class_loader);
} else {
return nullptr;
@@ -114,17 +119,30 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
return _godot_view;
}
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
_godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter));
return _godot_view;
}
void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
- if (_on_video_init)
+ if (_on_video_init) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _on_video_init);
+ p_env->CallVoidMethod(godot_instance, _on_video_init);
+ }
+}
+
+void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) {
+ if (_on_godot_setup_completed) {
+ if (p_env == nullptr) {
+ p_env = get_jni_env();
+ }
+ p_env->CallVoidMethod(godot_instance, _on_godot_setup_completed);
+ }
}
void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
@@ -132,29 +150,36 @@ void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
if (p_env == nullptr) {
p_env = get_jni_env();
}
+ ERR_FAIL_COND(p_env == nullptr);
+ p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
}
- p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
}
void GodotJavaWrapper::restart(JNIEnv *p_env) {
- if (_restart)
+ if (_restart) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _restart);
+ p_env->CallVoidMethod(godot_instance, _restart);
+ }
}
void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
- if (_finish)
+ if (_finish) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _finish);
+ p_env->CallVoidMethod(godot_instance, _finish);
+ }
}
void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
if (_set_keep_screen_on) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled);
}
}
@@ -162,6 +187,8 @@ void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
if (_alert) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
@@ -170,6 +197,8 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
int GodotJavaWrapper::get_gles_version_code() {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 0);
+
if (_get_GLES_version_code) {
return env->CallIntMethod(godot_instance, _get_GLES_version_code);
}
@@ -184,6 +213,8 @@ bool GodotJavaWrapper::has_get_clipboard() {
String GodotJavaWrapper::get_clipboard() {
if (_get_clipboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
+
jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard);
return jstring_to_string(s, env);
} else {
@@ -194,6 +225,8 @@ String GodotJavaWrapper::get_clipboard() {
String GodotJavaWrapper::get_input_fallback_mapping() {
if (_get_input_fallback_mapping) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
+
jstring fallback_mapping = (jstring)env->CallObjectMethod(godot_instance, _get_input_fallback_mapping);
return jstring_to_string(fallback_mapping, env);
} else {
@@ -208,6 +241,8 @@ bool GodotJavaWrapper::has_set_clipboard() {
void GodotJavaWrapper::set_clipboard(const String &p_text) {
if (_set_clipboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
}
@@ -216,6 +251,8 @@ void GodotJavaWrapper::set_clipboard(const String &p_text) {
bool GodotJavaWrapper::request_permission(const String &p_name) {
if (_request_permission) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
} else {
@@ -226,6 +263,8 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
bool GodotJavaWrapper::request_permissions() {
if (_request_permissions) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
return env->CallBooleanMethod(godot_instance, _request_permissions);
} else {
return false;
@@ -236,6 +275,8 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
Vector<String> permissions_list;
if (_get_granted_permissions) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, permissions_list);
+
jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions);
jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object);
@@ -254,6 +295,8 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
void GodotJavaWrapper::init_input_devices() {
if (_init_input_devices) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _init_input_devices);
}
}
@@ -261,6 +304,8 @@ void GodotJavaWrapper::init_input_devices() {
jobject GodotJavaWrapper::get_surface() {
if (_get_surface) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
return env->CallObjectMethod(godot_instance, _get_surface);
} else {
return nullptr;
@@ -270,6 +315,8 @@ jobject GodotJavaWrapper::get_surface() {
bool GodotJavaWrapper::is_activity_resumed() {
if (_is_activity_resumed) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
return env->CallBooleanMethod(godot_instance, _is_activity_resumed);
} else {
return false;
@@ -279,6 +326,8 @@ bool GodotJavaWrapper::is_activity_resumed() {
void GodotJavaWrapper::vibrate(int p_duration_ms) {
if (_vibrate) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms);
}
}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 99a60dffa1..0e20747a16 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -66,6 +66,7 @@ private:
jmethodID _is_activity_resumed = 0;
jmethodID _vibrate = 0;
jmethodID _get_input_fallback_mapping = 0;
+ jmethodID _on_godot_setup_completed = 0;
jmethodID _on_godot_main_loop_started = 0;
jmethodID _get_class_loader = 0;
@@ -80,6 +81,7 @@ public:
GodotJavaViewWrapper *get_godot_view();
void on_video_init(JNIEnv *p_env = nullptr);
+ void on_godot_setup_completed(JNIEnv *p_env = nullptr);
void on_godot_main_loop_started(JNIEnv *p_env = nullptr);
void restart(JNIEnv *p_env = nullptr);
void force_quit(JNIEnv *p_env = nullptr);
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index afcc7294f2..ba379c8d43 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -30,17 +30,34 @@
#include "thread_jandroid.h"
+#include <android/log.h>
+
#include "core/os/thread.h"
static JavaVM *java_vm = nullptr;
static thread_local JNIEnv *env = nullptr;
+// The logic here need to improve, init_thread/term_tread are designed to work with Thread::callback
+// Calling init_thread from setup_android_thread and get_jni_env to setup an env we're keeping and not detaching
+// could cause issues on app termination.
+//
+// We should be making sure that any thread started calls a nice cleanup function when it's done,
+// especially now that we use many more threads.
+
static void init_thread() {
+ if (env) {
+ // thread never detached! just keep using...
+ return;
+ }
+
java_vm->AttachCurrentThread(&env, nullptr);
}
static void term_thread() {
java_vm->DetachCurrentThread();
+
+ // this is no longer valid, must called init_thread to re-establish
+ env = nullptr;
}
void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
@@ -50,9 +67,17 @@ void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
}
void setup_android_thread() {
- init_thread();
+ if (!env) {
+ // !BAS! see remarks above
+ init_thread();
+ }
}
JNIEnv *get_jni_env() {
+ if (!env) {
+ // !BAS! see remarks above
+ init_thread();
+ }
+
return env;
}
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 17796beb6f..cf358e0878 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -54,7 +54,7 @@ def configure(env):
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["-O2", "-ftree-vectorize", "-fomit-frame-pointer"])
env.Append(LINKFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(LINKFLAGS=["-Os"])
diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm
index 887297848e..468fa2928a 100644
--- a/platform/iphone/godot_view.mm
+++ b/platform/iphone/godot_view.mm
@@ -39,6 +39,7 @@
#import <CoreMotion/CoreMotion.h>
static const int max_touches = 8;
+static const float earth_gravity = 9.80665;
@interface GodotView () {
UITouch *godot_touches[max_touches];
@@ -402,10 +403,19 @@ static const int max_touches = 8;
// https://developer.apple.com/reference/coremotion/cmmotionmanager?language=objc
// Apple splits our accelerometer date into a gravity and user movement
- // component. We add them back together
+ // component. We add them back together.
CMAcceleration gravity = self.motionManager.deviceMotion.gravity;
CMAcceleration acceleration = self.motionManager.deviceMotion.userAcceleration;
+ // To be consistent with Android we convert the unit of measurement from g (Earth's gravity)
+ // to m/s^2.
+ gravity.x *= earth_gravity;
+ gravity.y *= earth_gravity;
+ gravity.z *= earth_gravity;
+ acceleration.x *= earth_gravity;
+ acceleration.y *= earth_gravity;
+ acceleration.z *= earth_gravity;
+
///@TODO We don't seem to be getting data here, is my device broken or
/// is this code incorrect?
CMMagneticField magnetic = self.motionManager.deviceMotion.magneticField.field;
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index e80ef374ec..ac8d8de7e0 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -64,21 +64,21 @@ def configure(env):
sys.exit(255)
## Build type
- if env["target"] == "release":
+ if env["target"].startswith("release"):
# Use -Os to prioritize optimizing for reduced file size. This is
# particularly valuable for the web platform because it directly
# decreases download time.
# -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
# 100 KiB over -Os, which does not justify the negative impact on
# run-time performance.
- env.Append(CCFLAGS=["-Os"])
- env.Append(LINKFLAGS=["-Os"])
- elif env["target"] == "release_debug":
- env.Append(CCFLAGS=["-Os"])
- env.Append(LINKFLAGS=["-Os"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
- # Retain function names for backtraces at the cost of file size.
- env.Append(LINKFLAGS=["--profiling-funcs"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["-Os"])
+ env.Append(LINKFLAGS=["-Os"])
+
+ if env["target"] == "release_debug":
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ # Retain function names for backtraces at the cost of file size.
+ env.Append(LINKFLAGS=["--profiling-funcs"])
else: # "debug"
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(CCFLAGS=["-O1", "-g"])
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index 04fbba8a41..b3b15a1574 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -21,7 +21,11 @@ def get_build_version():
name = "custom_build"
if os.getenv("BUILD_NAME") != None:
name = os.getenv("BUILD_NAME")
- return "%d.%d.%d.%s.%s" % (version.major, version.minor, version.patch, version.status, name)
+ v = "%d.%d" % (version.major, version.minor)
+ if version.patch > 0:
+ v += ".%d" % version.patch
+ v += ".%s.%s" % (version.status, name)
+ return v
def create_engine_file(env, target, source, externs):
diff --git a/platform/javascript/js/engine/engine.js b/platform/javascript/js/engine/engine.js
index 19a0552c8c..7211ebbfd8 100644
--- a/platform/javascript/js/engine/engine.js
+++ b/platform/javascript/js/engine/engine.js
@@ -102,7 +102,7 @@ const Engine = (function () {
const me = this;
function doInit(promise) {
return promise.then(function (response) {
- return Godot(me.config.getModuleConfig(loadPath, response.clone()));
+ return Godot(me.config.getModuleConfig(loadPath, new Response(response.clone().body, { 'headers': [['content-type', 'application/wasm']] })));
}).then(function (module) {
const paths = me.config.persistentPaths;
return module['initFS'](paths).then(function (err) {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 09d185ae2b..6b527c6fb5 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -90,7 +90,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"]:
@@ -99,7 +99,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index c39a4426be..5b320da82f 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -50,7 +50,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"])
if env["arch"] != "arm64":
env.Prepend(CCFLAGS=["-msse2"])
@@ -61,7 +61,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"]:
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index f31d8b9b81..6ac98cae9c 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -159,6 +159,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
@@ -490,6 +491,10 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
args.push_back("-v"); /* provide some more feedback */
+ if (p_preset->get("codesign/replace_existing_signature")) {
+ args.push_back("-f");
+ }
+
args.push_back(p_path);
String str;
diff --git a/platform/server/detect.py b/platform/server/detect.py
index c799ce03e1..16ddbe1768 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -56,7 +56,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"]:
@@ -65,7 +65,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index fda8fdec66..28922a4f59 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -54,16 +54,19 @@ def configure(env):
## Build type
if env["target"] == "release":
- env.Append(CCFLAGS=["/O2", "/GL"])
env.Append(CCFLAGS=["/MD"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS", "/LTCG"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["/O2", "/GL"])
+ env.Append(LINKFLAGS=["/LTCG"])
elif env["target"] == "release_debug":
- env.Append(CCFLAGS=["/O2", "/Zi"])
env.Append(CCFLAGS=["/MD"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["/O2", "/Zi"])
elif env["target"] == "debug":
env.Append(CCFLAGS=["/Zi"])
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index fa97948395..33992069f9 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -62,6 +62,8 @@ using namespace Windows::Devices::Sensors;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace concurrency;
+static const float earth_gravity = 9.80665;
+
int OS_UWP::get_video_driver_count() const {
return 2;
}
@@ -372,9 +374,9 @@ void OS_UWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sende
AccelerometerReading ^ reading = args->Reading;
os->input->set_accelerometer(Vector3(
- reading->AccelerationX,
- reading->AccelerationY,
- reading->AccelerationZ));
+ reading->AccelerationX * earth_gravity,
+ reading->AccelerationY * earth_gravity,
+ reading->AccelerationZ * earth_gravity));
}
void OS_UWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, MagnetometerReadingChangedEventArgs ^ args) {
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index e24e466f88..e2d507eddd 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -36,7 +36,7 @@
#ifdef CRASH_HANDLER_EXCEPTION
-// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
+// Backtrace code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
#include <algorithm>
#include <iterator>
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index f26dea8d35..7772ba2dbe 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -72,6 +72,7 @@ def get_opts():
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
+ BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
]
@@ -190,18 +191,20 @@ def configure_msvc(env, manual_msvc_config):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
- else: # optimize for size
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
- env.Append(LINKFLAGS=["/OPT:REF"])
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
- else: # optimize for size
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
- env.Append(LINKFLAGS=["/OPT:REF"])
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
@@ -306,6 +309,12 @@ def configure_msvc(env, manual_msvc_config):
env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
+ # Sanitizers
+ if env["use_asan"]:
+ env.extra_suffix += ".s"
+ env.Append(LINKFLAGS=["/INFERASANLIBS"])
+ env.Append(CCFLAGS=["/fsanitize=address"])
+
# Incremental linking fix
env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
env["BUILDERS"]["Program"] = methods.precious_program
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b9b78f7bd4..e29faf4f3c 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1253,12 +1253,12 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
- // Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap
+ // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be white pixels of the monochrome bitmap
SetBkColor(hMainDC, clrTransparent);
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
- // Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap
+ // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be black and rest the pixels same as corresponding
// pixels of the source bitmap
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
@@ -2305,7 +2305,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_alt(alt_mem);
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
- // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not update recently.
+ // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently.
if (windows[window_id].last_pressure_update < 10) {
windows[window_id].last_pressure_update++;
} else {
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index f46a0dbe2e..b8679a87fe 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -110,12 +110,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
return false;
}
- dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
- if (!dev_list)
- return false;
+ dev_list = (PRAWINPUTDEVICELIST)memalloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
+ ERR_FAIL_NULL_V_MSG(dev_list, false, "Out of memory.");
if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
- free(dev_list);
+ memfree(dev_list);
return false;
}
for (unsigned int i = 0; i < dev_list_count; i++) {
@@ -130,11 +129,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) &&
(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) &&
(strstr(dev_name, "IG_") != nullptr)) {
- free(dev_list);
+ memfree(dev_list);
return true;
}
}
- free(dev_list);
+ memfree(dev_list);
return false;
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 3280a36e9b..1e9cdd241d 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -334,7 +334,7 @@ OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
}
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
- // For example on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
+ // For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
ret.bias = -info.Bias;
return ret;
}
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 56b620a6d9..c1f3827d15 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -53,7 +53,8 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
if (wlen < 0)
return;
- wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
+ wchar_t *wbuf = (wchar_t *)memalloc((len + 1) * sizeof(wchar_t));
+ ERR_FAIL_NULL_MSG(wbuf, "Out of memory.");
MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen);
wbuf[wlen] = 0;
@@ -62,7 +63,7 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
else
wprintf(L"%ls", wbuf);
- free(wbuf);
+ memfree(wbuf);
#ifdef DEBUG_ENABLED
fflush(stdout);
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index f39850441b..dfc08583f2 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -105,214 +105,6 @@ Rect2 AnimatedSprite2D::_get_rect() const {
return Rect2(ofs, s);
}
-void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) {
- E->get().frames.insert(p_at_pos, p_frame);
- } else {
- E->get().frames.push_back(p_frame);
- }
-
- emit_changed();
-}
-
-int SpriteFrames::get_frame_count(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- return E->get().frames.size();
-}
-
-void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- E->get().frames.remove(p_idx);
- emit_changed();
-}
-
-void SpriteFrames::clear(const StringName &p_anim) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- E->get().frames.clear();
- emit_changed();
-}
-
-void SpriteFrames::clear_all() {
- animations.clear();
- add_animation("default");
-}
-
-void SpriteFrames::add_animation(const StringName &p_anim) {
- ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
-
- animations[p_anim] = Anim();
-}
-
-bool SpriteFrames::has_animation(const StringName &p_anim) const {
- return animations.has(p_anim);
-}
-
-void SpriteFrames::remove_animation(const StringName &p_anim) {
- animations.erase(p_anim);
-}
-
-void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
- ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'.");
- ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists.");
-
- Anim anim = animations[p_prev];
- animations.erase(p_prev);
- animations[p_next] = anim;
-}
-
-Vector<String> SpriteFrames::_get_animation_list() const {
- Vector<String> ret;
- List<StringName> al;
- get_animation_list(&al);
- for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
- ret.push_back(E->get());
- }
-
- return ret;
-}
-
-void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
- for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- r_animations->push_back(E->key());
- }
-}
-
-Vector<String> SpriteFrames::get_animation_names() const {
- Vector<String> names;
- for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- names.push_back(E->key());
- }
- names.sort();
- return names;
-}
-
-void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
- ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().speed = p_fps;
-}
-
-float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().speed;
-}
-
-void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().loop = p_loop;
-}
-
-bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().loop;
-}
-
-void SpriteFrames::_set_frames(const Array &p_frames) {
- clear_all();
- Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
- ERR_FAIL_COND(!E);
-
- E->get().frames.resize(p_frames.size());
- for (int i = 0; i < E->get().frames.size(); i++) {
- E->get().frames.write[i] = p_frames[i];
- }
-}
-
-Array SpriteFrames::_get_frames() const {
- return Array();
-}
-
-Array SpriteFrames::_get_animations() const {
- Array anims;
- for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- Dictionary d;
- d["name"] = E->key();
- d["speed"] = E->get().speed;
- d["loop"] = E->get().loop;
- Array frames;
- for (int i = 0; i < E->get().frames.size(); i++) {
- frames.push_back(E->get().frames[i]);
- }
- d["frames"] = frames;
- anims.push_back(d);
- }
-
- return anims;
-}
-
-void SpriteFrames::_set_animations(const Array &p_animations) {
- animations.clear();
- for (int i = 0; i < p_animations.size(); i++) {
- Dictionary d = p_animations[i];
-
- ERR_CONTINUE(!d.has("name"));
- ERR_CONTINUE(!d.has("speed"));
- ERR_CONTINUE(!d.has("loop"));
- ERR_CONTINUE(!d.has("frames"));
-
- Anim anim;
- anim.speed = d["speed"];
- anim.loop = d["loop"];
- Array frames = d["frames"];
- for (int j = 0; j < frames.size(); j++) {
- RES res = frames[j];
- anim.frames.push_back(res);
- }
-
- animations[d["name"]] = anim;
- }
-}
-
-void SpriteFrames::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
- ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
- ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
- ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
-
- ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
-
- ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
- ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
-
- ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
- ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
-
- ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
- ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
- ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
- ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
- ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
- ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
-
- ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
- ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
-
- ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
- ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
-}
-
-SpriteFrames::SpriteFrames() {
- add_animation(SceneStringNames::get_singleton()->_default);
-}
-
void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
if (!frames.is_valid()) {
return;
@@ -590,6 +382,7 @@ bool AnimatedSprite2D::_is_playing() const {
}
void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+ ERR_FAIL_NULL_MSG(frames, "Can't play AnimatedSprite2D without a valid SpriteFrames resource.");
backwards = p_backwards;
if (p_animation) {
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 5e53a401e2..14ecb18866 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -32,74 +32,9 @@
#define ANIMATED_SPRITE_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/resources/sprite_frames.h"
#include "scene/resources/texture.h"
-class SpriteFrames : public Resource {
- GDCLASS(SpriteFrames, Resource);
-
- struct Anim {
- float speed = 5.0;
- bool loop = true;
- Vector<Ref<Texture2D>> frames;
- };
-
- Map<StringName, Anim> animations;
-
- Array _get_frames() const;
- void _set_frames(const Array &p_frames);
-
- Array _get_animations() const;
- void _set_animations(const Array &p_animations);
-
- Vector<String> _get_animation_list() const;
-
-protected:
- static void _bind_methods();
-
-public:
- void add_animation(const StringName &p_anim);
- bool has_animation(const StringName &p_anim) const;
- void remove_animation(const StringName &p_anim);
- void rename_animation(const StringName &p_prev, const StringName &p_next);
-
- void get_animation_list(List<StringName> *r_animations) const;
- Vector<String> get_animation_names() const;
-
- void set_animation_speed(const StringName &p_anim, float p_fps);
- float get_animation_speed(const StringName &p_anim) const;
-
- void set_animation_loop(const StringName &p_anim, bool p_loop);
- bool get_animation_loop(const StringName &p_anim) const;
-
- void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
- int get_frame_count(const StringName &p_anim) const;
- _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
- ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
- if (p_idx >= E->get().frames.size()) {
- return Ref<Texture2D>();
- }
-
- return E->get().frames[p_idx];
- }
-
- void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- ERR_FAIL_COND(p_idx < 0);
- if (p_idx >= E->get().frames.size()) {
- return;
- }
- E->get().frames.write[p_idx] = p_frame;
- }
- void remove_frame(const StringName &p_anim, int p_idx);
- void clear(const StringName &p_anim);
- void clear_all();
-
- SpriteFrames();
-};
-
class AnimatedSprite2D : public Node2D {
GDCLASS(AnimatedSprite2D, Node2D);
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 892ccadfda..c478f03356 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -375,7 +375,7 @@ void LineBuilder::build() {
}
if (intersection_result != SEGMENT_INTERSECT) {
- // In this case the joint is too corrputed to be re-used,
+ // In this case the joint is too corrupted to be re-used,
// start again the strip with fallback points
strip_begin(pos_up0, pos_down0, color1, uvx1);
}
@@ -485,7 +485,7 @@ void LineBuilder::strip_add_tri(Vector2 up, Orientation orientation) {
if (texture_mode != Line2D::LINE_TEXTURE_NONE) {
// UVs are just one slice of the texture all along
- // (otherwise we can't share the bottom vertice)
+ // (otherwise we can't share the bottom vertex)
uvs.push_back(uvs[_last_index[opposite_orientation]]);
}
@@ -520,7 +520,7 @@ void LineBuilder::strip_add_arc(Vector2 center, float angle_delta, Orientation o
strip_add_tri(rpos, orientation);
}
- // Last arc vertice
+ // Last arc vertex
rpos = center + Vector2(Math::cos(end_angle), Math::sin(end_angle)) * radius;
strip_add_tri(rpos, orientation);
}
@@ -569,7 +569,7 @@ void LineBuilder::new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Col
}
}
- // Last arc vertice
+ // Last arc vertex
Vector2 sc = Vector2(Math::cos(end_angle), Math::sin(end_angle));
rpos = center + sc * radius;
vertices.push_back(rpos);
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 794993f892..8be8c8db4a 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -364,8 +364,10 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
if (!enabled) {
NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
} else {
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) {
@@ -401,6 +403,7 @@ void NavigationRegion2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled) {
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -408,12 +411,14 @@ void NavigationRegion2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ if (enabled) {
+ NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
+ }
} break;
case NOTIFICATION_DRAW: {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) {
Vector<Vector2> verts = navpoly->get_vertices();
- int vsize = verts.size();
- if (vsize < 3) {
+ if (verts.size() < 3) {
return;
}
@@ -423,33 +428,47 @@ void NavigationRegion2D::_notification(int p_what) {
} else {
color = get_tree()->get_debug_navigation_disabled_color();
}
- Vector<Color> colors;
- Vector<Vector2> vertices;
- vertices.resize(vsize);
- colors.resize(vsize);
- {
- const Vector2 *vr = verts.ptr();
- for (int i = 0; i < vsize; i++) {
- vertices.write[i] = vr[i];
- colors.write[i] = color;
- }
- }
+ Color doors_color = color.lightened(0.2);
- Vector<int> indices;
+ RandomPCG rand;
for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
Vector<int> polygon = navpoly->get_polygon(i);
-
- for (int j = 2; j < polygon.size(); j++) {
- int kofs[3] = { 0, j - 1, j };
- for (int k = 0; k < 3; k++) {
- int idx = polygon[kofs[k]];
- ERR_FAIL_INDEX(idx, vsize);
- indices.push_back(idx);
- }
+ Vector<Vector2> vertices;
+ vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], verts.size());
+ vertices.write[j] = verts[polygon[j]];
}
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color;
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.a = color.a;
+ Vector<Color> colors;
+ colors.push_back(random_variation_color);
+
+ RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), vertices, colors);
+ }
+
+ // Draw the region
+ Transform2D xform = get_global_transform();
+ const NavigationServer2D *ns = NavigationServer2D::get_singleton();
+ float radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
+ for (int i = 0; i < ns->region_get_connections_count(region); i++) {
+ // Two main points
+ Vector2 a = ns->region_get_connection_pathway_start(region, i);
+ a = xform.affine_inverse().xform(a);
+ Vector2 b = ns->region_get_connection_pathway_end(region, i);
+ b = xform.affine_inverse().xform(b);
+ draw_line(a, b, doors_color);
+
+ // Draw a circle to illustrate the margins.
+ float angle = (b - a).angle();
+ draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color);
+ draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color);
}
- RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
}
} break;
}
@@ -484,6 +503,11 @@ void NavigationRegion2D::_navpoly_changed() {
update();
}
}
+void NavigationRegion2D::_map_changed(RID p_map) {
+ if (enabled && get_world_2d()->get_navigation_map() == p_map) {
+ update();
+ }
+}
String NavigationRegion2D::get_configuration_warning() const {
if (!is_visible_in_tree() || !is_inside_tree()) {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 7b471bd555..58f04599be 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -99,6 +99,7 @@ class NavigationRegion2D : public Node2D {
Ref<NavigationPolygon> navpoly;
void _navpoly_changed();
+ void _map_changed(RID p_RID);
protected:
void _notification(int p_what);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 96d8fb609b..a615d96687 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -411,13 +411,13 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
}
}
- //process remotions
+ //process removals
for (int i = 0; i < toremove_count; i++) {
_body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
- //process aditions
+ //process additions
for (int i = 0; i < toadd_count; i++) {
_body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 5728230a8c..e028b5f5b7 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -184,7 +184,7 @@ void Skeleton2D::_update_bone_setup() {
bone_setup_dirty = false;
RS::get_singleton()->skeleton_allocate_data(skeleton, bones.size(), true);
- bones.sort(); //sorty so they are always in the same order/index
+ bones.sort(); //sorting so that they are always in the same order/index
for (int i = 0; i < bones.size(); i++) {
bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 31040020dd..7c93edbff9 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -77,14 +77,14 @@ Rect2 Sprite2D::get_anchorable_rect() const {
return get_rect();
}
-void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
+void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const {
Rect2 base_rect;
- if (region) {
- r_filter_clip = region_filter_clip;
+ if (region_enabled) {
+ r_filter_clip_enabled = region_filter_clip_enabled;
base_rect = region_rect;
} else {
- r_filter_clip = false;
+ r_filter_clip_enabled = false;
base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
}
@@ -129,10 +129,10 @@ void Sprite2D::_notification(int p_what) {
*/
Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
+ bool filter_clip_enabled;
+ _get_rects(src_rect, dst_rect, filter_clip_enabled);
- texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip);
+ texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip_enabled);
} break;
}
}
@@ -199,18 +199,18 @@ bool Sprite2D::is_flipped_v() const {
return vflip;
}
-void Sprite2D::set_region(bool p_region) {
- if (p_region == region) {
+void Sprite2D::set_region_enabled(bool p_region_enabled) {
+ if (p_region_enabled == region_enabled) {
return;
}
- region = p_region;
+ region_enabled = p_region_enabled;
update();
notify_property_list_changed();
}
-bool Sprite2D::is_region() const {
- return region;
+bool Sprite2D::is_region_enabled() const {
+ return region_enabled;
}
void Sprite2D::set_region_rect(const Rect2 &p_region_rect) {
@@ -220,7 +220,7 @@ void Sprite2D::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
- if (region) {
+ if (region_enabled) {
item_rect_changed();
}
}
@@ -229,13 +229,13 @@ Rect2 Sprite2D::get_region_rect() const {
return region_rect;
}
-void Sprite2D::set_region_filter_clip(bool p_enable) {
- region_filter_clip = p_enable;
+void Sprite2D::set_region_filter_clip_enabled(bool p_region_filter_clip_enabled) {
+ region_filter_clip_enabled = p_region_filter_clip_enabled;
update();
}
bool Sprite2D::is_region_filter_clip_enabled() const {
- return region_filter_clip;
+ return region_filter_clip_enabled;
}
void Sprite2D::set_frame(int p_frame) {
@@ -299,8 +299,8 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const {
}
Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
+ bool filter_clip_enabled;
+ _get_rects(src_rect, dst_rect, filter_clip_enabled);
dst_rect.size = dst_rect.size.abs();
if (!dst_rect.has_point(p_point)) {
@@ -350,7 +350,7 @@ Rect2 Sprite2D::get_rect() const {
Size2i s;
- if (region) {
+ if (region_enabled) {
s = region_rect.size;
} else {
s = texture->get_size();
@@ -385,7 +385,7 @@ void Sprite2D::_validate_property(PropertyInfo &property) const {
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (!region && (property.name == "region_rect" || property.name == "region_filter_clip")) {
+ if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
@@ -414,15 +414,15 @@ void Sprite2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite2D::set_flip_v);
ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite2D::is_flipped_v);
- ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite2D::set_region);
- ClassDB::bind_method(D_METHOD("is_region"), &Sprite2D::is_region);
+ ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite2D::set_region_enabled);
+ ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite2D::is_region_enabled);
ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite2D::is_pixel_opaque);
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite2D::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite2D::get_region_rect);
- ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite2D::set_region_filter_clip);
+ ClassDB::bind_method(D_METHOD("set_region_filter_clip_enabled", "enabled"), &Sprite2D::set_region_filter_clip_enabled);
ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite2D::is_region_filter_clip_enabled);
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite2D::set_frame);
@@ -455,9 +455,9 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip_enabled"), "set_region_filter_clip_enabled", "is_region_filter_clip_enabled");
}
Sprite2D::Sprite2D() {
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
index fa765f457d..f6e9b4cde2 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -46,16 +46,16 @@ class Sprite2D : public Node2D {
bool hflip = false;
bool vflip = false;
- bool region = false;
+ bool region_enabled = false;
Rect2 region_rect;
- bool region_filter_clip = false;
+ bool region_filter_clip_enabled = false;
int frame = 0;
int vframes = 1;
int hframes = 1;
- void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const;
void _texture_changed();
@@ -97,10 +97,10 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_enabled);
+ bool is_region_enabled() const;
- void set_region_filter_clip(bool p_enable);
+ void set_region_filter_clip_enabled(bool p_enabled);
bool is_region_filter_clip_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 23eda379be..749cf4ff9d 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -211,7 +211,7 @@ void Area3D::_clear_monitoring() {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
- if (!node) { //node may have been deleted in previous frame or at other legiminate point
+ if (!node) { //node may have been deleted in previous frame or at other legitimate point
continue;
}
//ERR_CONTINUE(!node);
@@ -240,7 +240,7 @@ void Area3D::_clear_monitoring() {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
- if (!node) { //node may have been deleted in previous frame or at other legiminate point
+ if (!node) { //node may have been deleted in previous frame or at other legitimate point
continue;
}
//ERR_CONTINUE(!node);
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 402e2b8f40..95ffbe48c1 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -449,7 +449,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
ERR_FAIL_COND_V(p_simplex_indices.size() <= 1, 0); //should not happen, this is a bug
// Failed to separate the tetrahedrons using planes
- // this means Delaunay borked at some point.
+ // this means Delaunay broke at some point.
// Luckily, because we are using tetrahedrons, we can resort to
// less precise but still working ways to generate the separating plane
// this will most likely look bad when interpolating, but at least it will not crash.
@@ -511,7 +511,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
node.plane = best_plane;
if (indices_under.size() == 0) {
- //noting to do here
+ //nothing to do here
node.under = BSPNode::EMPTY_LEAF;
} else if (indices_under.size() == 1) {
node.under = -(indices_under[0] + 1);
@@ -520,7 +520,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
}
if (indices_over.size() == 0) {
- //noting to do here
+ //nothing to do here
node.over = BSPNode::EMPTY_LEAF;
} else if (indices_over.size() == 1) {
node.over = -(indices_over[0] + 1);
@@ -660,7 +660,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
}
// create mesh data for insert
- //get the base material textures, help compute altlas size and bounds
+ //get the base material textures, help compute atlas size and bounds
for (int m_i = 0; m_i < meshes_found.size(); m_i++) {
if (p_bake_step) {
float p = (float)(m_i) / meshes_found.size();
@@ -974,7 +974,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
images.push_back(lightmapper->get_bake_texture(i));
}
- //we assume they are all the same, so lets create a large one for saving
+ //we assume they are all the same, so let's create a large one for saving
Ref<Image> large_image;
large_image.instance();
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index f0623c625e..cd8d02233b 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -102,7 +102,7 @@ void Camera3D::_update_camera() {
void Camera3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD
+ // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD
// and Spatial will handle it first, including clearing its reference to the Viewport,
// therefore making it impossible to subclasses to access it
viewport = get_viewport();
@@ -715,7 +715,7 @@ void ClippedCamera3D::_notification(int p_what) {
Vector3 ray_from = parent_plane.project(cam_pos);
- clip_offset = 0; //reset by defau;t
+ clip_offset = 0; //reset by default
{ //check if points changed
Vector<Vector3> local_points = get_near_plane_points();
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 849ef7a2bf..39880db29c 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -30,6 +30,7 @@
#include "collision_object_3d.h"
+#include "core/config/engine.h"
#include "mesh_instance_3d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_server_3d.h"
@@ -139,7 +140,7 @@ void CollisionObject3D::_update_debug_shapes() {
}
void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) {
if (debug_shapes_to_update.is_empty()) {
call_deferred("_update_debug_shapes");
}
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 17a61b3e4d..e2cfc2ed87 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -348,7 +348,7 @@ void GPUParticles3D::_notification(int p_what) {
}
}
- // Use internal process when emitting and one_shot are on so that when
+ // Use internal process when emitting and one_shot is on so that when
// the shot ends the editor can properly update
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
if (one_shot && !is_emitting()) {
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 4575716f7a..ba0f8cc870 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -48,7 +48,7 @@
a) If above is invalid, don't keep invalidating upwards
2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below)
- drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow
+ drawback: setting/reading globals is useful and used very often, and using affine inverses is slow
---
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 6d135c8283..e225c1f22d 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -416,13 +416,13 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
}
}
- //process remotions
+ //process removals
for (int i = 0; i < toremove_count; i++) {
_body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
- //process aditions
+ //process additions
for (int i = 0; i < toadd_count; i++) {
_body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 465de2cb47..66f3e539a2 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -428,10 +428,10 @@ void RayCast3D::_update_debug_shape_material(bool p_check_collision) {
if (p_check_collision) {
if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
- // If base color is already quite reddish, hightlight collision with green color
+ // If base color is already quite reddish, highlight collision with green color
color = Color(0.0, 1.0, 0.0, color.a);
} else {
- // Else, hightlight collision with red color
+ // Else, highlight collision with red color
color = Color(1.0, 0, 0, color.a);
}
}
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 18c831e83d..85da546430 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -120,7 +120,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
if (p_force_simple_chain) {
// NOTE:
- // This is an "hack" that force to create only one tip per chain since the solver of multi tip (end effector)
+ // This is a "hack" that force to create only one tip per chain since the solver of multi tip (end effector)
// is not yet created.
// Remove this code when this is done
break;
@@ -268,6 +268,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
p_task->skeleton->set_bone_global_pose_override(p_task->chain.tips[i].chain_item->bone, Transform(), 0.0, true);
}
+ // Update the initial root transform
+ p_task->chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone);
+ p_task->chain.chain_root.current_pos = p_task->chain.chain_root.initial_transform.origin;
+
make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta);
if (p_use_magnet && p_task->chain.middle_chain_item) {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 2d8f22ab37..3fde4d6ef3 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -37,7 +37,6 @@
#include "scene/3d/collision_object_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/skeleton_3d.h"
-#include "servers/physics_server_3d.h"
SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
@@ -48,27 +47,28 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
mesh = p_mesh;
surface = p_surface;
-#ifndef _MSC_VER
-#warning Softbody is not working, needs to be redone considering that these functions no longer exist
-#endif
-#if 0
- const uint32_t surface_format = RS::get_singleton()->mesh_surface_get_format(mesh, surface);
- const int surface_vertex_len = RS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
- const int surface_index_len = RS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
+
+ RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh, surface);
+
uint32_t surface_offsets[RS::ARRAY_MAX];
+ uint32_t vertex_stride;
+ uint32_t attrib_stride;
+ uint32_t skin_stride;
+ RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, attrib_stride, skin_stride);
- buffer = RS::get_singleton()->mesh_surface_get_array(mesh, surface);
- stride = RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets);
+ buffer = surface_data.vertex_data;
+ stride = vertex_stride;
offset_vertices = surface_offsets[RS::ARRAY_VERTEX];
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
-#endif
}
void SoftBodyRenderingServerHandler::clear() {
- if (mesh.is_valid()) {
- buffer.resize(0);
- }
+ buffer.resize(0);
+ stride = 0;
+ offset_vertices = 0;
+ offset_normal = 0;
+ surface = 0;
mesh = RID();
}
@@ -77,7 +77,7 @@ void SoftBodyRenderingServerHandler::open() {
}
void SoftBodyRenderingServerHandler::close() {
- //write_buffer.release();
+ write_buffer = nullptr;
}
void SoftBodyRenderingServerHandler::commit_changes() {
@@ -309,6 +309,8 @@ void SoftBody3D::_notification(int p_what) {
}
void SoftBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
+
ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
@@ -337,18 +339,9 @@ void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
- ClassDB::bind_method(D_METHOD("set_angular_stiffness", "angular_stiffness"), &SoftBody3D::set_angular_stiffness);
- ClassDB::bind_method(D_METHOD("get_angular_stiffness"), &SoftBody3D::get_angular_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody3D::set_volume_stiffness);
- ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody3D::get_volume_stiffness);
-
ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody3D::set_pose_matching_coefficient);
- ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody3D::get_pose_matching_coefficient);
-
ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
@@ -366,12 +359,9 @@ void SoftBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_angular_stiffness", "get_angular_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
@@ -612,34 +602,10 @@ real_t SoftBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
-void SoftBody3D::set_angular_stiffness(real_t p_angular_stiffness) {
- PhysicsServer3D::get_singleton()->soft_body_set_angular_stiffness(physics_rid, p_angular_stiffness);
-}
-
-real_t SoftBody3D::get_angular_stiffness() {
- return PhysicsServer3D::get_singleton()->soft_body_get_angular_stiffness(physics_rid);
-}
-
-void SoftBody3D::set_volume_stiffness(real_t p_volume_stiffness) {
- PhysicsServer3D::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
-}
-
-real_t SoftBody3D::get_volume_stiffness() {
- return PhysicsServer3D::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
-}
-
real_t SoftBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
-void SoftBody3D::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
- PhysicsServer3D::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
-}
-
-real_t SoftBody3D::get_pose_matching_coefficient() {
- return PhysicsServer3D::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
-}
-
void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
@@ -768,7 +734,9 @@ void SoftBody3D::_reset_points_offsets() {
PinnedPoint *w = pinned_points.ptrw();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!r[i].spatial_attachment) {
- w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path));
+ if (!r[i].spatial_attachment_path.is_empty() && has_node(r[i].spatial_attachment_path)) {
+ w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path));
+ }
}
if (!r[i].spatial_attachment) {
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 6e24a530bd..f98df39209 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -32,10 +32,11 @@
#define SOFT_PHYSICS_BODY_H
#include "scene/3d/mesh_instance_3d.h"
+#include "servers/physics_server_3d.h"
class SoftBody3D;
-class SoftBodyRenderingServerHandler {
+class SoftBodyRenderingServerHandler : public RenderingServerHandler {
friend class SoftBody3D;
RID mesh;
@@ -57,9 +58,9 @@ private:
void commit_changes();
public:
- void set_vertex(int p_vertex_id, const void *p_vector3);
- void set_normal(int p_vertex_id, const void *p_vector3);
- void set_aabb(const AABB &p_aabb);
+ void set_vertex(int p_vertex_id, const void *p_vector3) override;
+ void set_normal(int p_vertex_id, const void *p_vector3) override;
+ void set_aabb(const AABB &p_aabb) override;
};
class SoftBody3D : public MeshInstance3D {
@@ -122,6 +123,8 @@ public:
void prepare_physics_server();
void become_mesh_owner();
+ RID get_physics_rid() const { return physics_rid; }
+
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
@@ -149,18 +152,9 @@ public:
void set_linear_stiffness(real_t p_linear_stiffness);
real_t get_linear_stiffness();
- void set_angular_stiffness(real_t p_angular_stiffness);
- real_t get_angular_stiffness();
-
- void set_volume_stiffness(real_t p_volume_stiffness);
- real_t get_volume_stiffness();
-
void set_pressure_coefficient(real_t p_pressure_coefficient);
real_t get_pressure_coefficient();
- void set_pose_matching_coefficient(real_t p_pose_matching_coefficient);
- real_t get_pose_matching_coefficient();
-
void set_damping_coefficient(real_t p_damping_coefficient);
real_t get_damping_coefficient();
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index b7a3135bd5..0be54e7243 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -366,7 +366,7 @@ void Sprite3D::_draw() {
}
Rect2 base_rect;
- if (region) {
+ if (region_enabled) {
base_rect = region_rect;
} else {
base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
@@ -511,24 +511,24 @@ Ref<Texture2D> Sprite3D::get_texture() const {
return texture;
}
-void Sprite3D::set_region(bool p_region) {
- if (p_region == region) {
+void Sprite3D::set_region_enabled(bool p_region_enabled) {
+ if (p_region_enabled == region_enabled) {
return;
}
- region = p_region;
+ region_enabled = p_region_enabled;
_queue_update();
notify_property_list_changed();
}
-bool Sprite3D::is_region() const {
- return region;
+bool Sprite3D::is_region_enabled() const {
+ return region_enabled;
}
void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
bool changed = region_rect != p_region_rect;
region_rect = p_region_rect;
- if (region && changed) {
+ if (region_enabled && changed) {
_queue_update();
}
}
@@ -595,7 +595,7 @@ Rect2 Sprite3D::get_item_rect() const {
Size2i s;
- if (region) {
+ if (region_enabled) {
s = region_rect.size;
} else {
s = texture->get_size();
@@ -625,7 +625,7 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (!region && property.name == "region_rect") {
+ if (!region_enabled && property.name == "region_rect") {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
@@ -634,8 +634,8 @@ void Sprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite3D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &Sprite3D::get_texture);
- ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite3D::set_region);
- ClassDB::bind_method(D_METHOD("is_region"), &Sprite3D::is_region);
+ ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite3D::set_region_enabled);
+ ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite3D::is_region_enabled);
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite3D::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite3D::get_region_rect);
@@ -659,14 +659,14 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_SIGNAL(MethodInfo("frame_changed"));
}
Sprite3D::Sprite3D() {
- region = false;
+ region_enabled = false;
frame = 0;
vframes = 1;
hframes = 1;
@@ -692,7 +692,7 @@ void AnimatedSprite3D::_draw() {
Ref<Texture2D> texture = frames->get_frame(animation, frame);
if (!texture.is_valid()) {
- return; //no texuture no life
+ return; //no texture no life
}
Vector2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0) {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index a9ce2d8eee..b48660eb2d 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -31,8 +31,8 @@
#ifndef SPRITE_3D_H
#define SPRITE_3D_H
-#include "scene/2d/animated_sprite_2d.h"
#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/sprite_frames.h"
class SpriteBase3D : public GeometryInstance3D {
GDCLASS(SpriteBase3D, GeometryInstance3D);
@@ -107,8 +107,8 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_region_enabled);
+ bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
@@ -147,7 +147,7 @@ class Sprite3D : public SpriteBase3D {
GDCLASS(Sprite3D, SpriteBase3D);
Ref<Texture2D> texture;
- bool region;
+ bool region_enabled;
Rect2 region_rect;
int frame;
@@ -167,8 +167,8 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_region_enabled);
+ bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 8b774444b9..5b0b3b89d3 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -563,7 +563,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
b2invmass);
// FIXME: rel_vel assignment here is overwritten by the following assignment.
- // What seems to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel);
+ // What seems to be intended in the next assignment is: rel_vel = normal.dot(rel_vel);
// Investigate why.
real_t rel_vel = jac.getRelativeVelocity(
s->get_linear_velocity(),
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 17c8596e8f..16718b956f 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -151,7 +151,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
Vector2 uv;
Vector3 lnormal;
get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
- if (lnormal == Vector3()) { //just in case normal as nor provided
+ if (lnormal == Vector3()) { //just in case normal is not provided
lnormal = normal;
}
@@ -183,7 +183,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
Vector3 lnormal;
Vector2 uv;
get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
- if (lnormal == Vector3()) { //just in case normal as nor provided
+ if (lnormal == Vector3()) { //just in case normal is not provided
lnormal = normal;
}
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 2c19307c52..0c1798a876 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -605,7 +605,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
}
if (p_seeked) {
- //find whathever should be playing
+ //find whatever should be playing
int idx = a->track_find_key(i, p_time);
if (idx < 0) {
continue;
@@ -634,7 +634,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->audio_playing = true;
playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
nc->audio_len = len - start_ofs - end_ofs;
} else {
nc->audio_len = 0;
@@ -665,7 +665,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->audio_playing = true;
playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
nc->audio_len = len - start_ofs - end_ofs;
} else {
nc->audio_len = 0;
@@ -1343,7 +1343,7 @@ void AnimationPlayer::_stop_playing_caches() {
}
void AnimationPlayer::_node_removed(Node *p_node) {
- clear_caches(); // nodes contained here ar being removed, clear the caches
+ clear_caches(); // nodes contained here are being removed, clear the caches
}
void AnimationPlayer::clear_caches() {
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 26a13f33c9..4b4d3943c9 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1009,7 +1009,7 @@ void AnimationTree::_process_graph(float p_delta) {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
if (seeked) {
- //find whathever should be playing
+ //find whatever should be playing
int idx = a->track_find_key(i, time);
if (idx < 0) {
continue;
@@ -1038,7 +1038,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->playing = true;
playing_caches.insert(t);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
t->len = len - start_ofs - end_ofs;
} else {
t->len = 0;
@@ -1069,7 +1069,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->playing = true;
playing_caches.insert(t);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
t->len = len - start_ofs - end_ofs;
} else {
t->len = 0;
@@ -1337,6 +1337,7 @@ void AnimationTree::_tree_changed() {
}
void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) {
+ ERR_FAIL_COND(node.is_null());
if (!property_parent_map.has(p_base_path)) {
property_parent_map[p_base_path] = HashMap<StringName, StringName>();
}
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index eb35979a47..2030808724 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -1115,7 +1115,7 @@ real_t Tween::tell() const {
// For each interpolation...
for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
- // Get the data and figure out if it's position is further along than the previous ones
+ // Get the data and figure out if its position is further along than the previous ones
const InterpolateData &data = E->get();
if (data.elapsed > pos) {
// Save it if so
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 2853a8b9d9..1478cbf69e 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -171,7 +171,7 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
if (active.is_set() && stream_playback.is_valid() && !stream_paused) {
//changing streams out of the blue is not a great idea, but at least
- //lets try to somehow avoid a click
+ //let's try to somehow avoid a click
AudioFrame *buffer = fadeout_buffer.ptrw();
int buffer_size = fadeout_buffer.size();
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 4dbe3cc1c4..a1d4adcd41 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -487,7 +487,7 @@ void LiveEditor::_send_tree() {
}
Array arr;
- // Encoded as a flat list depth fist.
+ // Encoded as a flat list depth first.
SceneDebuggerTree tree(scene_tree->root);
tree.serialize(arr);
EngineDebugger::get_singleton()->send_message("scene:scene_tree", arr);
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index c570438b6a..7407ad5b8f 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -313,7 +313,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const {
return align;
}
-void BoxContainer::add_spacer(bool p_begin) {
+Control *BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew(Control);
c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events
@@ -327,6 +327,8 @@ void BoxContainer::add_spacer(bool p_begin) {
if (p_begin) {
move_child(c, 0);
}
+
+ return c;
}
BoxContainer::BoxContainer(bool p_vertical) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index 31050d1feb..23feea565c 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -55,7 +55,7 @@ protected:
static void _bind_methods();
public:
- void add_spacer(bool p_begin = false);
+ Control *add_spacer(bool p_begin = false);
void set_alignment(AlignMode p_align);
AlignMode get_alignment() const;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f188e63743..c13bce5e0c 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -96,6 +96,7 @@ void Control::_edit_set_state(const Dictionary &p_state) {
void Control::_edit_set_position(const Point2 &p_position) {
#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins.");
set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled() && Object::cast_to<Control>(data.parent));
#else
// Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED
@@ -117,6 +118,7 @@ Size2 Control::_edit_get_scale() const {
void Control::_edit_set_rect(const Rect2 &p_edit_rect) {
#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins.");
set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled());
set_size(p_edit_rect.size.snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled());
#else
@@ -584,7 +586,7 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
- // some parents need to know the order of the childrens to draw (like TabContainer)
+ // some parents need to know the order of the children to draw (like TabContainer)
// update if necessary
if (data.parent) {
data.parent->update();
@@ -1782,7 +1784,7 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a icon
+ // clear if "null" is passed instead of an icon
if (p_icon.is_null()) {
data.icon_override.erase(p_name);
} else {
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 2882c4286b..7ad4ac80c9 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -731,9 +731,9 @@ FileDialog::Access FileDialog::get_access() const {
}
void FileDialog::_make_dir_confirm() {
- Error err = dir_access->make_dir(makedirname->get_text());
+ Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
if (err == OK) {
- dir_access->change_dir(makedirname->get_text());
+ dir_access->change_dir(makedirname->get_text().strip_edges());
invalidate();
update_filters();
update_dir();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 331f0380c5..71d31434d4 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -180,7 +180,12 @@ void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
accept_event();
} else if (mm.is_valid() && is_pressing) {
if (is_resizing) {
- ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative());
+ // Prevent setting minimap wider than GraphEdit
+ Vector2 new_minimap_size;
+ new_minimap_size.x = MIN(get_size().x - mm->get_relative().x, ge->get_size().x - 2.0 * minimap_padding.x);
+ new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y);
+ ge->set_minimap_size(new_minimap_size);
+
update();
} else {
Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
@@ -1312,25 +1317,17 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
minimap->update();
}
- if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
- //too difficult to get right
- //set_zoom(zoom*ZOOM_SCALE);
- }
-
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) {
- //too difficult to get right
- //set_zoom(zoom/ZOOM_SCALE);
- }
- if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom(zoom * ZOOM_SCALE);
+ } else if (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom(zoom / ZOOM_SCALE);
+ } else if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ } else if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8);
}
}
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index b615cdb266..c80fc516e8 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -32,6 +32,12 @@
#include "core/string/translation.h"
+struct _MinSizeCache {
+ int min_size;
+ bool will_stretch;
+ int final_size;
+};
+
bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
String str = p_name;
if (str.begins_with("opentype_features/")) {
@@ -171,15 +177,23 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
}
void GraphNode::_resort() {
- int sep = get_theme_constant("separation");
+ /** First pass, determine minimum size AND amount of stretchable elements */
+
+ Size2i new_size = get_size();
Ref<StyleBox> sb = get_theme_stylebox("frame");
- bool first = true;
- Size2 minsize;
+ int sep = get_theme_constant("separation");
+
+ bool first = true;
+ int children_count = 0;
+ int stretch_min = 0;
+ int stretch_avail = 0;
+ float stretch_ratio_total = 0;
+ Map<Control *, _MinSizeCache> min_size_cache;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c) {
+ if (!c || !c->is_visible_in_tree()) {
continue;
}
if (c->is_set_as_top_level()) {
@@ -187,38 +201,120 @@ void GraphNode::_resort() {
}
Size2i size = c->get_combined_minimum_size();
+ _MinSizeCache msc;
- minsize.y += size.y;
- minsize.x = MAX(minsize.x, size.x);
+ stretch_min += size.height;
+ msc.min_size = size.height;
+ msc.will_stretch = c->get_v_size_flags() & SIZE_EXPAND;
- if (first) {
- first = false;
- } else {
- minsize.y += sep;
+ if (msc.will_stretch) {
+ stretch_avail += msc.min_size;
+ stretch_ratio_total += c->get_stretch_ratio();
}
+ msc.final_size = msc.min_size;
+ min_size_cache[c] = msc;
+ children_count++;
}
- int vofs = 0;
- int w = get_size().x - sb->get_minimum_size().x;
+ if (children_count == 0) {
+ return;
+ }
+
+ int stretch_max = new_size.height - (children_count - 1) * sep;
+ int stretch_diff = stretch_max - stretch_min;
+ if (stretch_diff < 0) {
+ //avoid negative stretch space
+ stretch_diff = 0;
+ }
+
+ stretch_avail += stretch_diff - sb->get_margin(SIDE_BOTTOM) - sb->get_margin(SIDE_TOP); //available stretch space.
+ /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable
+ elements exist */
+
+ while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist
+ bool refit_successful = true; //assume refit-test will go well
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (!c || !c->is_visible_in_tree()) {
+ continue;
+ }
+ if (c->is_set_as_top_level()) {
+ continue;
+ }
+ ERR_FAIL_COND(!min_size_cache.has(c));
+ _MinSizeCache &msc = min_size_cache[c];
+
+ if (msc.will_stretch) { //wants to stretch
+ //let's see if it can really stretch
+
+ int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
+ if (final_pixel_size < msc.min_size) {
+ //if available stretching area is too small for widget,
+ //then remove it from stretching area
+ msc.will_stretch = false;
+ stretch_ratio_total -= c->get_stretch_ratio();
+ refit_successful = false;
+ stretch_avail -= msc.min_size;
+ msc.final_size = msc.min_size;
+ break;
+ } else {
+ msc.final_size = final_pixel_size;
+ }
+ }
+ }
+
+ if (refit_successful) { //uf refit went well, break
+ break;
+ }
+ }
+
+ /** Final pass, draw and stretch elements **/
+
+ int ofs = sb->get_margin(SIDE_TOP);
+
+ first = true;
+ int idx = 0;
cache_y.clear();
+ int w = new_size.width - sb->get_minimum_size().x;
+
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c) {
+ if (!c || !c->is_visible_in_tree()) {
continue;
}
if (c->is_set_as_top_level()) {
continue;
}
- Size2i size = c->get_combined_minimum_size();
+ _MinSizeCache &msc = min_size_cache[c];
+
+ if (first) {
+ first = false;
+ } else {
+ ofs += sep;
+ }
- Rect2 r(sb->get_margin(SIDE_LEFT), sb->get_margin(SIDE_TOP) + vofs, w, size.y);
+ int from = ofs;
+ int to = ofs + msc.final_size;
- fit_child_in_rect(c, r);
- cache_y.push_back(vofs + size.y * 0.5);
+ if (msc.will_stretch && idx == children_count - 1) {
+ //adjust so the last one always fits perfect
+ //compensating for numerical imprecision
- vofs += size.y + sep;
+ to = new_size.height - sb->get_margin(SIDE_BOTTOM);
+ }
+
+ int size = to - from;
+
+ Rect2 rect(sb->get_margin(SIDE_LEFT), from, w, size);
+
+ fit_child_in_rect(c, rect);
+ cache_y.push_back(from - sb->get_margin(SIDE_TOP) + size * 0.5);
+
+ ofs = to;
+ idx++;
}
update();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 7afc04c51c..fa72599fb3 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -768,7 +768,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
} else if (p_event->is_action("ui_accept")) {
- search_string = ""; //any mousepress cance
+ search_string = ""; //any mousepress cancels
if (current >= 0 && current < items.size()) {
emit_signal("item_activated", current);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index f674e717f3..ce371e3b56 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -809,7 +809,7 @@ void LineEdit::_notification(int p_what) {
}
} else {
{
- // IME intermidiet text range.
+ // IME intermediate text range.
Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos, cursor_pos + ime_text.length());
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
@@ -1436,7 +1436,7 @@ void LineEdit::set_cursor_position(int p_pos) {
ofs_max -= r_icon->get_width();
}
- // Note: Use too coordinates to fit IME input range.
+ // Note: Use two coordinates to fit IME input range.
Vector2i primary_catret_offset = get_cursor_pixel_pos();
if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index f237f79be1..fb9e2647ee 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -222,7 +222,7 @@ void PopupMenu::_activate_submenu(int p_over) {
submenu_popup->set_close_on_parent_focus(false);
submenu_popup->set_position(submenu_pos);
- submenu_popup->set_as_minsize(); // Shrink the popup size to it's contents.
+ submenu_popup->set_as_minsize(); // Shrink the popup size to its contents.
submenu_popup->popup();
// Set autohide areas
@@ -722,6 +722,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = 0; i < items.size(); i++) {
items.write[i].xl_text = tr(items[i].text);
items.write[i].dirty = true;
+ _shape_item(i);
}
child_controls_changed();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index ed319f9fd0..bce30e7cd3 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -147,7 +147,7 @@ RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item
case ITEM_TEXT: {
ItemText *t = (ItemText *)it;
offset += t->text.length();
- if (offset >= p_position) {
+ if (offset > p_position) {
return it;
}
} break;
@@ -588,7 +588,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
row_height = MAX(yofs, row_height);
- if (column == col_count - 1) {
+ // Add row height after last column of the row or last cell of the table.
+ if (column == col_count - 1 || E->next() == nullptr) {
offset.x = 0;
row_height += vseparation;
table->total_height += row_height;
@@ -1117,7 +1118,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
while (ofs.y < size.height && from_line < main->lines.size()) {
- ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ ofs.y += main->lines[from_line].text_buf->get_size().y;
if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
if (r_outside != nullptr) {
*r_outside = false;
@@ -1244,8 +1246,19 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (r_click_item != nullptr) {
Item *it = p_frame->lines[p_line].from;
Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
- it = _get_item_at_pos(it, it_to, char_pos);
- *r_click_item = it;
+ if (char_pos == p_frame->lines[p_line].char_count) {
+ // Selection after the end of line, select last item.
+ if (it_to != nullptr) {
+ *r_click_item = _get_prev_item(it_to);
+ } else {
+ for (Item *i = it; i && i != it_to; i = _get_next_item(i)) {
+ *r_click_item = i;
+ }
+ }
+ } else {
+ // Selection in the line.
+ *r_click_item = _get_item_at_pos(it, it_to, char_pos);
+ }
}
if (r_click_frame != nullptr) {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index e3e3f549de..3bf163f670 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -645,7 +645,7 @@ int TabContainer::_get_tab_width(int p_index) const {
// Get the width of the text displayed on the tab.
Ref<Font> font = get_theme_font("font");
int font_size = get_theme_font_size("font_size");
- String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(control->get_name());
+ String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name()));
int width = font->get_string_size(text, font_size).width;
// Add space for a tab icon.
@@ -1023,6 +1023,7 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = _get_tab(p_tab);
ERR_FAIL_COND(!child);
child->set_meta("_tab_name", p_title);
+ _refresh_texts();
update();
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5c17f929bc..cf3978ca41 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -808,7 +808,7 @@ void TextEdit::_notification(int p_what) {
// Get the highlighted words.
String highlighted_text = get_selection_text();
- // Check if highlighted words contains only whitespaces (tabs or spaces).
+ // Check if highlighted words contain only whitespaces (tabs or spaces).
bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
int cursor_wrap_index = get_cursor_wrap_index();
@@ -1057,7 +1057,7 @@ void TextEdit::_notification(int p_what) {
}
if (str.length() == 0) {
- // Draw line background if empty as we won't loop at at all.
+ // Draw line background if empty as we won't loop at all.
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), cache.current_line_color);
@@ -1442,7 +1442,7 @@ void TextEdit::_notification(int p_what) {
}
} else {
{
- // IME intermidiet text range.
+ // IME Intermediate text range.
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, cursor.column, cursor.column + ime_text.length());
for (int j = 0; j < sel.size(); j++) {
Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
@@ -1557,7 +1557,7 @@ void TextEdit::_notification(int p_what) {
completion_rect.position.x = rect_left_border_x;
}
- if (cursor_pos.y + row_height + total_height > get_size().height) {
+ if (cursor_pos.y + row_height + total_height > get_size().height && cursor_pos.y > total_height) {
// Completion panel above the cursor line
completion_rect.position.y = cursor_pos.y - total_height;
} else {
@@ -2009,7 +2009,7 @@ void TextEdit::indent_selected_lines_right() {
// We don't really care where selection is - we just need to know indentation level at the beginning of the line.
int left = _find_first_non_whitespace_column_of_line(line_text);
int spaces_to_add = _calculate_spaces_till_next_right_indent(left);
- // Since we will add this much spaces we want move whole selection and cursor by this much.
+ // Since we will add these many spaces, we want to move the whole selection and cursor by this much.
selection_offset = spaces_to_add;
for (int j = 0; j < spaces_to_add; j++) {
line_text = ' ' + line_text;
@@ -2034,7 +2034,7 @@ void TextEdit::indent_selected_lines_left() {
int end_line;
// Moving cursor and selection after unindenting can get tricky because
- // changing content of line can move cursor and selection on it's own (if new line ends before previous position of either),
+ // changing content of line can move cursor and selection on its own (if new line ends before previous position of either),
// therefore we just remember initial values and at the end of the operation offset them by number of removed characters.
int removed_characters = 0;
int initial_selection_end_column = selection.to_column;
@@ -2454,7 +2454,7 @@ void TextEdit::_move_cursor_to_line_start(bool p_select) {
row_start_col += rows[i].length();
}
if (cursor.column == row_start_col || wi == 0) {
- // Compute whitespace symbols seq length.
+ // Compute whitespace symbols sequence length.
int current_line_whitespace_len = 0;
while (current_line_whitespace_len < text[cursor.line].length()) {
char32_t c = text[cursor.line][current_line_whitespace_len];
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6ac4d7fd2f..0445e5f345 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -410,6 +410,14 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::uncollapse_tree() {
+ TreeItem *t = this;
+ while (t) {
+ t->set_collapsed(false);
+ t = t->parent;
+ }
+}
+
void TreeItem::set_custom_minimum_height(int p_height) {
custom_min_height = p_height;
_changed_notify();
@@ -842,6 +850,8 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
+ ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
+
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
@@ -3506,9 +3516,13 @@ int Tree::get_column_width(int p_column) const {
return columns[p_column].min_width;
}
+ int expand_area = get_size().width;
+
Ref<StyleBox> bg = cache.bg;
- int expand_area = get_size().width - (bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT));
+ if (bg.is_valid()) {
+ expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
+ }
if (v_scroll->is_visible_in_tree()) {
expand_area -= v_scroll->get_combined_minimum_size().width;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 1be21cb4a4..d1407e24d4 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -229,6 +229,8 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void uncollapse_tree();
+
void set_custom_minimum_height(int p_height);
int get_custom_minimum_height() const;
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 71c372aec2..e4ed5c6e6c 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -335,7 +335,7 @@ bool HTTPRequest::_update_connection() {
call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
return true;
- // Request migh have been done
+ // Request might have been done
} else {
// Did not request yet, do request
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 4c6bcb10b2..933f67db68 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -428,7 +428,7 @@ void Node::set_process_mode(ProcessMode p_mode) {
_propagate_process_owner(data.process_owner, pause_notification);
#ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
- // Its very expensive during runtime to change, so editor-only
+ // It's very expensive during runtime to change, so editor-only
if (Engine::get_singleton()->is_editor_hint()) {
get_tree()->emit_signal("tree_process_mode_changed");
}
@@ -1130,7 +1130,7 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new nade is needed, create one.
+ //no name and a new name is needed, create one.
name = p_child->get_class();
// Adjust casing according to project setting. The current type name is expected to be in PascalCase.
@@ -1156,7 +1156,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
bool exists = false;
for (int i = 0; i < cc; i++) {
- if (children_ptr[i] == p_child) { //exclude self in renaming if its already a child
+ if (children_ptr[i] == p_child) { //exclude self in renaming if it's already a child
continue;
}
if (children_ptr[i]->data.name == name) {
@@ -1945,7 +1945,7 @@ void Node::set_editable_instance(Node *p_node, bool p_editable) {
if (!p_editable) {
p_node->data.editable_instance = false;
// Avoid this flag being needlessly saved;
- // also give more visual feedback if editable children is re-enabled
+ // also give more visual feedback if editable children are re-enabled
set_display_folded(false);
} else {
p_node->data.editable_instance = true;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9aaddfd373..66f3a2ebde 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -389,6 +389,7 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
}
void SceneTree::initialize() {
+ ERR_FAIL_COND(!root);
initialized = true;
root->_set_tree(this);
MainLoop::initialize();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 40b85e6d7b..e4cda4b96f 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1163,7 +1163,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (p_world_2d.is_valid()) {
world_2d = p_world_2d;
} else {
- WARN_PRINT("Invalid world_3d");
+ WARN_PRINT("Invalid world_2d");
world_2d = Ref<World2D>(memnew(World2D));
}
@@ -2201,7 +2201,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
embedder = this;
viewport_pos = mpos;
} else {
- //not an embeder, but may be a subwindow of an embedder
+ //not an embedder, but may be a subwindow of an embedder
Window *w = Object::cast_to<Window>(this);
if (w) {
if (w->is_embedded()) {
@@ -2393,7 +2393,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//keyboard focus
//if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
Ref<InputEventKey> k = p_event;
- //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/righ/etc> is handled here when it shouldn't be.
+ //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be.
bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
if (from && p_event->is_pressed()) {
@@ -2672,7 +2672,7 @@ void Viewport::_post_gui_grab_click_focus() {
Ref<InputEventMouseButton> mb;
mb.instance();
- //send unclic
+ //send unclick
mb->set_position(click);
mb->set_button_index(i + 1);
@@ -2690,7 +2690,7 @@ void Viewport::_post_gui_grab_click_focus() {
Ref<InputEventMouseButton> mb;
mb.instance();
- //send clic
+ //send click
mb->set_position(click);
mb->set_button_index(i + 1);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 8f3e82ad73..bacb0030bb 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -897,12 +897,13 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
+ /*
Window *focus_target = exclusive_child;
focus_target->grab_focus();
while (focus_target->exclusive_child != nullptr) {
focus_target = focus_target->exclusive_child;
focus_target->grab_focus();
- }
+ }*/
if (!is_embedding_subwindows()) { //not embedding, no need for event
return;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index cc1dafd0db..6f64ac6d04 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2738,7 +2738,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
if (d > pd.length() * p_alowed_linear_err) {
- return false; //beyond allowed error for colinearity
+ return false; //beyond allowed error for collinearity
}
if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_alowed_angular_err) {
@@ -2828,7 +2828,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
if (d > pd.length() * p_alowed_linear_err) {
- return false; //beyond allowed error for colinearity
+ return false; //beyond allowed error for collinearity
}
t[2] = (d1 - d0) / (d2 - d0);
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 8ffc7b4b4c..3cc1af59ae 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -285,7 +285,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
| 4 | |
+---+---+
- this normally go RIGHT, but if its coming from RIGHT, it should go LEFT
+ this normally go RIGHT, but if it's coming from RIGHT, it should go LEFT
*/
if (case6s.has(Point2i(curx, cury))) {
//found, so we go left, and delete from case6s;
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index f067695d7d..3fed700383 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -35,13 +35,12 @@
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
Set<DrawEdge> edges;
- Vector<Vector3> data = get_faces();
- int datalen = data.size();
- ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
+ int index_count = faces.size();
+ ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
- const Vector3 *r = data.ptr();
+ const Vector3 *r = faces.ptr();
- for (int i = 0; i < datalen; i += 3) {
+ for (int i = 0; i < index_count; i += 3) {
for (int j = 0; j < 3; j++) {
DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
edges.insert(de);
@@ -71,22 +70,46 @@ real_t ConcavePolygonShape3D::get_enclosing_radius() const {
}
void ConcavePolygonShape3D::_update_shape() {
+ Dictionary d;
+ d["faces"] = faces;
+ d["backface_collision"] = backface_collision;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+
Shape3D::_update_shape();
}
void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
- PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), p_faces);
+ faces = p_faces;
+ _update_shape();
notify_change_to_owners();
}
Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
- return PhysicsServer3D::get_singleton()->shape_get_data(get_shape());
+ return faces;
+}
+
+void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
+ backface_collision = p_enabled;
+
+ if (!faces.is_empty()) {
+ _update_shape();
+ notify_change_to_owners();
+ }
+}
+
+bool ConcavePolygonShape3D::is_backface_collision_enabled() const {
+ return backface_collision;
}
void ConcavePolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces);
+
+ ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled);
+ ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled");
}
ConcavePolygonShape3D::ConcavePolygonShape3D() :
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index 391459a3d7..bb28359dcc 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -36,6 +36,9 @@
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
+ Vector<Vector3> faces;
+ bool backface_collision = false;
+
struct DrawEdge {
Vector3 a;
Vector3 b;
@@ -65,6 +68,9 @@ public:
void set_faces(const Vector<Vector3> &p_faces);
Vector<Vector3> get_faces() const;
+ void set_backface_collision_enabled(bool p_enabled);
+ bool is_backface_collision_enabled() const;
+
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 9931757cc4..0d02bde90d 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1703,7 +1703,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
- // you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash
+ // you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH);
// alpha anti aliasiasing is only enabled when you can select aa
const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa;
@@ -1722,7 +1722,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- // we cant choose an antialiasing mode if alpha isnt possible
+ // we can't choose an antialiasing mode if alpha isn't possible
if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
property.usage = 0;
}
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 167540eb77..a0f4bf9409 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -1075,7 +1075,7 @@ ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() cons
void ParticlesMaterial::set_sub_emitter_frequency(float p_frequency) {
sub_emitter_frequency = p_frequency;
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pas delta instead of frequency, since its easier to compute
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute
}
float ParticlesMaterial::get_sub_emitter_frequency() const {
return sub_emitter_frequency;
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index f292140d6b..536318ed16 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -77,7 +77,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
outside_point.x += 20.451 + Math::randf() * 10.2039;
outside_point.y += 21.193 + Math::randf() * 12.5412;
- //insert edges (which are also connetions)
+ //insert edges (which are also connections)
for (int i = 0; i < p_connections.size(); i += 2) {
Edge e(p_connections[i], p_connections[i + 1]);
@@ -335,7 +335,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
//oh this was visited already, can we win the cost?
if (p.distance > distance) {
- p.prev = least_cost_point; //reasign previous
+ p.prev = least_cost_point; //reassign previous
p.distance = distance;
}
} else {
diff --git a/scene/resources/ray_shape_2d.cpp b/scene/resources/ray_shape_2d.cpp
index d2125445fa..fb8f4b9985 100644
--- a/scene/resources/ray_shape_2d.cpp
+++ b/scene/resources/ray_shape_2d.cpp
@@ -42,17 +42,33 @@ void RayShape2D::_update_shape() {
}
void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- Vector2 tip = Vector2(0, get_length());
- RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3);
+ const Vector2 target_position = Vector2(0, get_length());
+
+ const float max_arrow_size = 6;
+ const float line_width = 1.4;
+ bool no_line = target_position.length() < line_width;
+ float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
+
+ if (no_line) {
+ arrow_size = target_position.length();
+ } else {
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), target_position - target_position.normalized() * arrow_size, p_color, line_width);
+ }
+
+ Transform2D xf;
+ xf.rotate(target_position.angle());
+ xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
+
Vector<Vector2> pts;
- float tsize = 4.0;
- pts.push_back(tip + Vector2(0, tsize));
- pts.push_back(tip + Vector2(Math_SQRT12 * tsize, 0));
- pts.push_back(tip + Vector2(-Math_SQRT12 * tsize, 0));
+ pts.push_back(xf.xform(Vector2(arrow_size, 0)));
+ pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size)));
+ pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size)));
+
Vector<Color> cols;
for (int i = 0; i < 3; i++) {
cols.push_back(p_color);
}
+
RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID());
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 7ca532e1d6..f2751b7604 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1321,7 +1321,7 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
- return ""; //could not rwead
+ return ""; //could not read
}
ResourceLoaderText loader;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
new file mode 100644
index 0000000000..90c702081b
--- /dev/null
+++ b/scene/resources/sprite_frames.cpp
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* sprite_frames.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "sprite_frames.h"
+
+#include "scene/scene_string_names.h"
+
+void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) {
+ E->get().frames.insert(p_at_pos, p_frame);
+ } else {
+ E->get().frames.push_back(p_frame);
+ }
+
+ emit_changed();
+}
+
+int SpriteFrames::get_frame_count(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ return E->get().frames.size();
+}
+
+void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ E->get().frames.remove(p_idx);
+ emit_changed();
+}
+
+void SpriteFrames::clear(const StringName &p_anim) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ E->get().frames.clear();
+ emit_changed();
+}
+
+void SpriteFrames::clear_all() {
+ animations.clear();
+ add_animation("default");
+}
+
+void SpriteFrames::add_animation(const StringName &p_anim) {
+ ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
+
+ animations[p_anim] = Anim();
+}
+
+bool SpriteFrames::has_animation(const StringName &p_anim) const {
+ return animations.has(p_anim);
+}
+
+void SpriteFrames::remove_animation(const StringName &p_anim) {
+ animations.erase(p_anim);
+}
+
+void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
+ ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'.");
+ ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists.");
+
+ Anim anim = animations[p_prev];
+ animations.erase(p_prev);
+ animations[p_next] = anim;
+}
+
+Vector<String> SpriteFrames::_get_animation_list() const {
+ Vector<String> ret;
+ List<StringName> al;
+ get_animation_list(&al);
+ for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
+ ret.push_back(E->get());
+ }
+
+ return ret;
+}
+
+void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
+ for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ r_animations->push_back(E->key());
+ }
+}
+
+Vector<String> SpriteFrames::get_animation_names() const {
+ Vector<String> names;
+ for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ names.push_back(E->key());
+ }
+ names.sort();
+ return names;
+}
+
+void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
+ ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ E->get().speed = p_fps;
+}
+
+float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+ return E->get().speed;
+}
+
+void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ E->get().loop = p_loop;
+}
+
+bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
+ return E->get().loop;
+}
+
+void SpriteFrames::_set_frames(const Array &p_frames) {
+ clear_all();
+ Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
+ ERR_FAIL_COND(!E);
+
+ E->get().frames.resize(p_frames.size());
+ for (int i = 0; i < E->get().frames.size(); i++) {
+ E->get().frames.write[i] = p_frames[i];
+ }
+}
+
+Array SpriteFrames::_get_frames() const {
+ return Array();
+}
+
+Array SpriteFrames::_get_animations() const {
+ Array anims;
+ for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ Dictionary d;
+ d["name"] = E->key();
+ d["speed"] = E->get().speed;
+ d["loop"] = E->get().loop;
+ Array frames;
+ for (int i = 0; i < E->get().frames.size(); i++) {
+ frames.push_back(E->get().frames[i]);
+ }
+ d["frames"] = frames;
+ anims.push_back(d);
+ }
+
+ return anims;
+}
+
+void SpriteFrames::_set_animations(const Array &p_animations) {
+ animations.clear();
+ for (int i = 0; i < p_animations.size(); i++) {
+ Dictionary d = p_animations[i];
+
+ ERR_CONTINUE(!d.has("name"));
+ ERR_CONTINUE(!d.has("speed"));
+ ERR_CONTINUE(!d.has("loop"));
+ ERR_CONTINUE(!d.has("frames"));
+
+ Anim anim;
+ anim.speed = d["speed"];
+ anim.loop = d["loop"];
+ Array frames = d["frames"];
+ for (int j = 0; j < frames.size(); j++) {
+ RES res = frames[j];
+ anim.frames.push_back(res);
+ }
+
+ animations[d["name"]] = anim;
+ }
+}
+
+void SpriteFrames::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
+ ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
+ ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
+ ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
+
+ ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
+
+ ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
+ ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
+
+ ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
+ ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
+
+ ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
+ ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
+ ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
+ ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
+ ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
+ ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
+
+ ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
+ ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
+
+ ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
+ ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+}
+
+SpriteFrames::SpriteFrames() {
+ add_animation(SceneStringNames::get_singleton()->_default);
+}
diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h
new file mode 100644
index 0000000000..282c5f20ab
--- /dev/null
+++ b/scene/resources/sprite_frames.h
@@ -0,0 +1,102 @@
+/*************************************************************************/
+/* sprite_frames.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 SPRITE_FRAMES_H
+#define SPRITE_FRAMES_H
+
+#include "scene/resources/texture.h"
+
+class SpriteFrames : public Resource {
+ GDCLASS(SpriteFrames, Resource);
+
+ struct Anim {
+ float speed = 5.0;
+ bool loop = true;
+ Vector<Ref<Texture2D>> frames;
+ };
+
+ Map<StringName, Anim> animations;
+
+ Array _get_frames() const;
+ void _set_frames(const Array &p_frames);
+
+ Array _get_animations() const;
+ void _set_animations(const Array &p_animations);
+
+ Vector<String> _get_animation_list() const;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void add_animation(const StringName &p_anim);
+ bool has_animation(const StringName &p_anim) const;
+ void remove_animation(const StringName &p_anim);
+ void rename_animation(const StringName &p_prev, const StringName &p_next);
+
+ void get_animation_list(List<StringName> *r_animations) const;
+ Vector<String> get_animation_names() const;
+
+ void set_animation_speed(const StringName &p_anim, float p_fps);
+ float get_animation_speed(const StringName &p_anim) const;
+
+ void set_animation_loop(const StringName &p_anim, bool p_loop);
+ bool get_animation_loop(const StringName &p_anim) const;
+
+ void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
+ int get_frame_count(const StringName &p_anim) const;
+ _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+ if (p_idx >= E->get().frames.size()) {
+ return Ref<Texture2D>();
+ }
+
+ return E->get().frames[p_idx];
+ }
+
+ void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND(p_idx < 0);
+ if (p_idx >= E->get().frames.size()) {
+ return;
+ }
+ E->get().frames.write[p_idx] = p_frame;
+ }
+ void remove_frame(const StringName &p_anim, int p_idx);
+ void clear(const StringName &p_anim);
+ void clear_all();
+
+ SpriteFrames();
+};
+
+#endif // SPRITE_FRAMES_H
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 47933bd69a..3d3900ecc5 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -1059,6 +1059,10 @@ void SurfaceTool::set_material(const Ref<Material> &p_material) {
material = p_material;
}
+Ref<Material> SurfaceTool::get_material() const {
+ return material;
+}
+
void SurfaceTool::clear() {
begun = false;
primitive = Mesh::PRIMITIVE_LINES;
@@ -1088,6 +1092,10 @@ void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
ERR_FAIL_COND(begun);
last_custom_format[p_index] = p_format;
}
+
+Mesh::PrimitiveType SurfaceTool::get_primitive() const {
+ return primitive;
+}
SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
return last_custom_format[p_index];
@@ -1174,6 +1182,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
+ ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 17efdcba71..28addf2245 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -143,6 +143,8 @@ public:
void set_custom_format(int p_index, CustomFormat p_format);
CustomFormat get_custom_format(int p_index) const;
+ Mesh::PrimitiveType get_primitive() const;
+
void begin(Mesh::PrimitiveType p_primitive);
void set_color(Color p_color);
@@ -171,6 +173,7 @@ public:
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
void clear();
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index a064ade362..ccdc5bebd0 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -368,7 +368,7 @@ World2D::World2D() {
navigation_map = NavigationServer2D::get_singleton()->map_create();
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10));
- NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 100));
+ NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5));
indexer = memnew(SpatialIndexer2D);
}
diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp
index 37e4122e50..78837c7531 100644
--- a/servers/audio/effects/audio_effect_capture.cpp
+++ b/servers/audio/effects/audio_effect_capture.cpp
@@ -91,8 +91,6 @@ Ref<AudioEffectInstance> AudioEffectCapture::instance() {
}
void AudioEffectCapture::set_buffer_length(float p_buffer_length_seconds) {
- ERR_FAIL_COND(buffer_initialized);
-
buffer_length_seconds = p_buffer_length_seconds;
}
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index be812cf62d..eab4c61591 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -184,9 +184,10 @@ CameraFeed::~CameraFeed() {
#endif
}
-void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
+void CameraFeed::set_RGB_img(const Ref<Image> &p_rgb_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_rgb_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -207,9 +208,10 @@ void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
#endif
}
-void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
+void CameraFeed::set_YCbCr_img(const Ref<Image> &p_ycbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_ycbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -230,9 +232,11 @@ void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
#endif
}
-void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
+void CameraFeed::set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_y_img.is_null());
+ ERR_FAIL_COND(p_cbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index fc02af4249..eb4ef155bc 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -100,9 +100,9 @@ public:
virtual ~CameraFeed();
FeedDataType get_datatype() const;
- void set_RGB_img(Ref<Image> p_rgb_img);
- void set_YCbCr_img(Ref<Image> p_ycbcr_img);
- void set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img);
+ void set_RGB_img(const Ref<Image> &p_rgb_img);
+ void set_YCbCr_img(const Ref<Image> &p_ycbcr_img);
+ void set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img);
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
void allocate_texture(int p_width, int p_height, Image::Format p_format, RenderingServer::TextureType p_texture_type, FeedDataType p_data_type);
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index fee74f3dbc..9e32bc209b 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -132,7 +132,8 @@ static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
static Transform trf2_to_trf3(const Transform2D &d) {
Vector3 o(v2_to_v3(d.get_origin()));
Basis b;
- b.rotate(Vector3(0, 1, 0), d.get_rotation());
+ b.rotate(Vector3(0, -1, 0), d.get_rotation());
+ b.scale(v2_to_v3(d.get_scale()));
return Transform(b, o);
}
@@ -156,6 +157,10 @@ static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
}
}
+void NavigationServer2D::_emit_map_changed(RID p_map) {
+ emit_signal("map_changed", p_map);
+}
+
void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
@@ -174,6 +179,9 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_layers", "region"), &NavigationServer2D::region_get_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &NavigationServer2D::region_set_navpoly);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
@@ -189,10 +197,14 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer2D::agent_set_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("free", "object"), &NavigationServer2D::free);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
NavigationServer2D::NavigationServer2D() {
singleton = this;
+ ERR_FAIL_COND_MSG(!NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one.");
+ NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed));
}
NavigationServer2D::~NavigationServer2D() {
@@ -226,6 +238,10 @@ void NavigationServer2D::region_set_navpoly(RID p_region, Ref<NavigationPolygon>
NavigationServer3D::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh));
}
+int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+
RID NavigationServer2D::agent_create() const {
RID agent = NavigationServer3D::get_singleton()->agent_create();
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 46c8f6a71d..d56c719839 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -45,12 +45,14 @@ class NavigationServer2D : public Object {
static NavigationServer2D *singleton;
+ void _emit_map_changed(RID p_map);
+
protected:
static void _bind_methods();
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer2D *get_singleton() { return singleton; }
+ static NavigationServer2D *get_singleton() { return singleton; }
/// MUST be used in single thread!
static NavigationServer2D *get_singleton_mut() { return singleton; }
@@ -98,6 +100,11 @@ public:
/// Set the navigation poly of this region.
virtual void region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const;
+ virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
+ virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+
/// Creates the agent.
virtual RID agent_create() const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index d81ce70af6..b0047a250a 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -59,6 +59,9 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer3D::region_set_navmesh);
ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer3D::region_bake_navmesh);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
@@ -77,9 +80,11 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer3D::set_active);
ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
-const NavigationServer3D *NavigationServer3D::get_singleton() {
+NavigationServer3D *NavigationServer3D::get_singleton() {
return singleton;
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index beed19d563..420f9c9c18 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -55,7 +55,7 @@ protected:
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer3D *get_singleton();
+ static NavigationServer3D *get_singleton();
/// MUST be used in single thread!
static NavigationServer3D *get_singleton_mut();
@@ -111,9 +111,14 @@ public:
/// Set the navigation mesh of this region.
virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0;
- /// Bake the navigation mesh
+ /// Bake the navigation mesh.
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const = 0;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
+
/// Creates the agent.
virtual RID agent_create() const = 0;
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index feced36a2b..da70ac7d4b 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -221,11 +221,21 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) {
bool BodyPair2DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
+ bool report_contacts_only = false;
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -350,51 +360,44 @@ bool BodyPair2DSW::setup(real_t p_step) {
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
+ c.active = false;
+
Vector2 global_A = xform_Au.xform(c.local_A);
Vector2 global_B = xform_Bu.xform(c.local_B);
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0 || !c.reused) {
- c.active = false;
continue;
}
- c.active = true;
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
#endif
- int gather_A = A->can_report_contacts();
- int gather_B = B->can_report_contacts();
c.rA = global_A;
c.rB = global_B - offset_B;
- if (gather_A | gather_B) {
- //Vector2 crB( -B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x );
-
- global_A += offset_A;
- global_B += offset_A;
+ if (A->can_report_contacts()) {
+ Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
+ A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
+ }
- if (gather_A) {
- Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
- A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
- }
- if (gather_B) {
- Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
- B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
- }
+ if (B->can_report_contacts()) {
+ Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
+ B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
}
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
- c.active = false;
+ if (report_contacts_only) {
collided = false;
continue;
}
+ c.active = true;
+
// Precompute normal mass, tangent mass, and bias.
real_t rnA = c.rA.dot(c.normal);
real_t rnB = c.rB.dot(c.normal);
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 9eff14bbeb..64ba0cb09d 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -501,20 +501,18 @@ void Body3DSW::integrate_forces(real_t p_step) {
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
- linear_velocity = (new_transform.origin - get_transform().origin) / p_step;
+ motion = new_transform.origin - get_transform().origin;
+ do_motion = true;
+ linear_velocity = motion / p_step;
//compute a FAKE angular velocity, not so easy
- Basis rot = new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
+ Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
Vector3 axis;
real_t angle;
rot.get_axis_angle(axis, angle);
axis.normalize();
- angular_velocity = axis.normalized() * (angle / p_step);
-
- motion = new_transform.origin - get_transform().origin;
- do_motion = true;
-
+ angular_velocity = axis * (angle / p_step);
} else {
if (!omit_force_integration && !first_integration) {
//overridden by direct state query
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 8e21003a5f..e87ff2364b 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -290,10 +290,10 @@ public:
void update_inertias();
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
- _FORCE_INLINE_ Vector3 get_inv_inertia() const { return _inv_inertia; }
- _FORCE_INLINE_ Basis get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
+ _FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; }
+ _FORCE_INLINE_ const Basis &get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
- _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
+ _FORCE_INLINE_ const Vector3 &get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock);
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 6012ff1522..36114c0c91 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -49,12 +49,12 @@
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
-void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
BodyPair3DSW *pair = (BodyPair3DSW *)p_userdata;
- pair->contact_added_callback(p_point_A, p_point_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
}
-void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
// check if we already have the contact
//Vector3 local_A = A->get_inv_transform().xform(p_point_A);
@@ -73,6 +73,8 @@ void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector
contact.acc_bias_impulse = 0;
contact.acc_bias_impulse_center_of_mass = 0;
contact.acc_tangent_impulse = Vector3();
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
contact.local_A = local_A;
contact.local_B = local_B;
contact.normal = (p_point_A - p_point_B).normalized();
@@ -211,11 +213,21 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) {
bool BodyPair3DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
+ bool report_contacts_only = false;
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -279,12 +291,9 @@ bool BodyPair3DSW::setup(real_t p_step) {
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0) {
- c.active = false;
continue;
}
- c.active = true;
-
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
@@ -308,6 +317,11 @@ bool BodyPair3DSW::setup(real_t p_step) {
B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
}
+ if (report_contacts_only) {
+ collided = false;
+ continue;
+ }
+
c.active = true;
// Precompute normal mass, tangent mass, and bias.
@@ -456,7 +470,7 @@ void BodyPair3DSW::solve(real_t p_step) {
}
BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B) :
- Constraint3DSW(_arr, 2) {
+ BodyContact3DSW(_arr, 2) {
A = p_A;
B = p_B;
shape_A = p_shape_A;
@@ -472,3 +486,305 @@ BodyPair3DSW::~BodyPair3DSW() {
A->remove_constraint(this);
B->remove_constraint(this);
}
+
+void BodySoftBodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ BodySoftBodyPair3DSW *pair = (BodySoftBodyPair3DSW *)p_userdata;
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+}
+
+void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+ Vector3 local_A = body->get_inv_transform().xform(p_point_A);
+ Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B);
+
+ Contact contact;
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
+ contact.acc_normal_impulse = 0;
+ contact.acc_bias_impulse = 0;
+ contact.acc_bias_impulse_center_of_mass = 0;
+ contact.acc_tangent_impulse = Vector3();
+ contact.local_A = local_A;
+ contact.local_B = local_B;
+ contact.normal = (p_point_A - p_point_B).normalized();
+ contact.mass_normal = 0;
+
+ // Attempt to determine if the contact will be reused.
+ real_t contact_recycle_radius = space->get_contact_recycle_radius();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (c.index_B == p_index_B) {
+ if (c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
+ c.local_B.distance_squared_to(local_B) < (contact_recycle_radius * contact_recycle_radius)) {
+ contact.acc_normal_impulse = c.acc_normal_impulse;
+ contact.acc_bias_impulse = c.acc_bias_impulse;
+ contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
+ contact.acc_tangent_impulse = c.acc_tangent_impulse;
+ }
+ c = contact;
+ return;
+ }
+ }
+
+ contacts.push_back(contact);
+}
+
+void BodySoftBodyPair3DSW::validate_contacts() {
+ // Make sure to erase contacts that are no longer valid.
+ const Transform &transform_A = body->get_transform();
+
+ real_t contact_max_separation = space->get_contact_max_separation();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+
+ Vector3 global_A = transform_A.xform(c.local_A);
+ Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
+
+ if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) {
+ // Contact no longer needed, remove.
+ if ((contact_index + 1) < contact_count) {
+ // Swap with the last one.
+ SWAP(c, contacts[contact_count - 1]);
+ }
+
+ contact_index--;
+ contact_count--;
+ }
+ }
+
+ contacts.resize(contact_count);
+}
+
+bool BodySoftBodyPair3DSW::setup(real_t p_step) {
+ if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
+ collided = false;
+ return false;
+ }
+
+ if (body->is_shape_set_as_disabled(body_shape)) {
+ collided = false;
+ return false;
+ }
+
+ const Transform &xform_Au = body->get_transform();
+ Transform xform_A = xform_Au * body->get_shape_transform(body_shape);
+
+ Transform xform_Bu = soft_body->get_transform();
+ Transform xform_B = xform_Bu * soft_body->get_shape_transform(0);
+
+ validate_contacts();
+
+ Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
+ Shape3DSW *shape_B_ptr = soft_body->get_shape(0);
+
+ bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
+ this->collided = collided;
+
+ real_t max_penetration = space->get_contact_max_allowed_penetration();
+
+ real_t bias = (real_t)0.3;
+ if (shape_A_ptr->get_custom_bias()) {
+ bias = shape_A_ptr->get_custom_bias();
+ }
+
+ real_t inv_dt = 1.0 / p_step;
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ c.active = false;
+
+ real_t node_inv_mass = soft_body->get_node_inv_mass(c.index_B);
+ if (node_inv_mass == 0.0) {
+ continue;
+ }
+
+ Vector3 global_A = xform_Au.xform(c.local_A);
+ Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
+
+ real_t depth = c.normal.dot(global_A - global_B);
+
+ if (depth <= 0) {
+ continue;
+ }
+
+ c.active = true;
+
+#ifdef DEBUG_ENABLED
+
+ if (space->is_debugging_contacts()) {
+ space->add_debug_contact(global_A);
+ space->add_debug_contact(global_B);
+ }
+#endif
+
+ c.rA = global_A - xform_Au.origin - body->get_center_of_mass();
+ c.rB = global_B;
+
+ if (body->can_report_contacts()) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA) + body->get_linear_velocity();
+ body->add_contact(global_A, -c.normal, depth, body_shape, global_B, 0, soft_body->get_instance_id(), soft_body->get_self(), crA);
+ }
+
+ if (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ body->set_active(true);
+ }
+
+ // Precompute normal mass, tangent mass, and bias.
+ Vector3 inertia_A = body->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
+ real_t kNormal = body->get_inv_mass() + node_inv_mass;
+ kNormal += c.normal.dot(inertia_A.cross(c.rA));
+ c.mass_normal = 1.0f / kNormal;
+
+ c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);
+ c.depth = depth;
+
+ Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
+ body->apply_impulse(c.rA + body->get_center_of_mass(), -j_vec);
+ soft_body->apply_node_impulse(c.index_B, j_vec);
+ c.acc_bias_impulse = 0;
+ c.acc_bias_impulse_center_of_mass = 0;
+
+ c.bounce = body->get_bounce();
+
+ if (c.bounce) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ c.bounce = c.bounce * dv.dot(c.normal);
+ }
+ }
+
+ return true;
+}
+
+void BodySoftBodyPair3DSW::solve(real_t p_step) {
+ if (!collided) {
+ return;
+ }
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (!c.active) {
+ continue;
+ }
+
+ c.active = false;
+
+ // Bias impulse.
+ Vector3 crbA = body->get_biased_angular_velocity().cross(c.rA);
+ Vector3 dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ real_t vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn = (-vbn + c.bias) * c.mass_normal;
+ real_t jbnOld = c.acc_bias_impulse;
+ c.acc_bias_impulse = MAX(jbnOld + jbn, 0.0f);
+
+ Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
+
+ body->apply_bias_impulse(c.rA + body->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
+ soft_body->apply_node_bias_impulse(c.index_B, jb);
+
+ crbA = body->get_biased_angular_velocity().cross(c.rA);
+ dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn_com = (-vbn + c.bias) / (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B));
+ real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
+ c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
+
+ Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
+
+ body->apply_bias_impulse(body->get_center_of_mass(), -jb_com, 0.0f);
+ soft_body->apply_node_bias_impulse(c.index_B, -jb_com);
+ }
+
+ c.active = true;
+ }
+
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ real_t vn = dv.dot(c.normal);
+
+ if (Math::abs(vn) > MIN_VELOCITY) {
+ real_t jn = -(c.bounce + vn) * c.mass_normal;
+ real_t jnOld = c.acc_normal_impulse;
+ c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
+
+ Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
+
+ body->apply_impulse(c.rA + body->get_center_of_mass(), -j);
+ soft_body->apply_node_impulse(c.index_B, j);
+
+ c.active = true;
+ }
+
+ // Friction impulse.
+ real_t friction = body->get_friction();
+
+ Vector3 lvA = body->get_linear_velocity() + body->get_angular_velocity().cross(c.rA);
+ Vector3 lvB = soft_body->get_node_velocity(c.index_B);
+ Vector3 dtv = lvB - lvA;
+
+ real_t tn = c.normal.dot(dtv);
+
+ // Tangential velocity.
+ Vector3 tv = dtv - c.normal * tn;
+ real_t tvl = tv.length();
+
+ if (tvl > MIN_VELOCITY) {
+ tv /= tvl;
+
+ Vector3 temp1 = body->get_inv_inertia_tensor().xform(c.rA.cross(tv));
+
+ real_t t = -tvl /
+ (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B) + tv.dot(temp1.cross(c.rA)));
+
+ Vector3 jt = t * tv;
+
+ Vector3 jtOld = c.acc_tangent_impulse;
+ c.acc_tangent_impulse += jt;
+
+ real_t fi_len = c.acc_tangent_impulse.length();
+ real_t jtMax = c.acc_normal_impulse * friction;
+
+ if (fi_len > CMP_EPSILON && fi_len > jtMax) {
+ c.acc_tangent_impulse *= jtMax / fi_len;
+ }
+
+ jt = c.acc_tangent_impulse - jtOld;
+
+ body->apply_impulse(c.rA + body->get_center_of_mass(), -jt);
+ soft_body->apply_node_impulse(c.index_B, jt);
+
+ c.active = true;
+ }
+ }
+}
+
+BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) {
+ body = p_A;
+ soft_body = p_B;
+ body_shape = p_shape_A;
+ space = p_A->get_space();
+ body->add_constraint(this, 0);
+ soft_body->add_constraint(this);
+}
+
+BodySoftBodyPair3DSW::~BodySoftBodyPair3DSW() {
+ body->remove_constraint(this);
+ soft_body->remove_constraint(this);
+}
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
index 4d049eafdc..74dddfa6aa 100644
--- a/servers/physics_3d/body_pair_3d_sw.h
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -28,32 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_PAIR_SW_H
-#define BODY_PAIR_SW_H
+#ifndef BODY_PAIR_3D_SW_H
+#define BODY_PAIR_3D_SW_H
#include "body_3d_sw.h"
#include "constraint_3d_sw.h"
+#include "core/templates/local_vector.h"
+#include "soft_body_3d_sw.h"
-class BodyPair3DSW : public Constraint3DSW {
- enum {
- MAX_CONTACTS = 4
- };
-
- union {
- struct {
- Body3DSW *A;
- Body3DSW *B;
- };
-
- Body3DSW *_arr[2];
- };
-
- int shape_A;
- int shape_B;
-
+class BodyContact3DSW : public Constraint3DSW {
+protected:
struct Contact {
Vector3 position;
Vector3 normal;
+ int index_A, index_B;
Vector3 local_A, local_B;
real_t acc_normal_impulse; // accumulated normal impulse (Pn)
Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
@@ -68,22 +56,45 @@ class BodyPair3DSW : public Constraint3DSW {
Vector3 rA, rB; // Offset in world orientation with respect to center of mass
};
+ Vector3 sep_axis;
+ bool collided;
+
+ Space3DSW *space;
+
+ BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
+ Constraint3DSW(p_body_ptr, p_body_count) {
+ }
+};
+
+class BodyPair3DSW : public BodyContact3DSW {
+ enum {
+ MAX_CONTACTS = 4
+ };
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ int shape_A;
+ int shape_B;
+
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
- Vector3 sep_axis;
Contact contacts[MAX_CONTACTS];
int contact_count;
- bool collided;
- static void _contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
- void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B);
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
void validate_contacts();
bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B);
- Space3DSW *space;
-
public:
bool setup(real_t p_step);
void solve(real_t p_step);
@@ -92,4 +103,26 @@ public:
~BodyPair3DSW();
};
-#endif // BODY_PAIR__SW_H
+class BodySoftBodyPair3DSW : public BodyContact3DSW {
+ Body3DSW *body;
+ SoftBody3DSW *soft_body;
+
+ int body_shape;
+
+ LocalVector<Contact> contacts;
+
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
+
+ void validate_contacts();
+
+public:
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B);
+ ~BodySoftBodyPair3DSW();
+};
+
+#endif // BODY_PAIR_3D_SW_H
diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h
index 3847b81381..85221b7746 100644
--- a/servers/physics_3d/collision_object_3d_sw.h
+++ b/servers/physics_3d/collision_object_3d_sw.h
@@ -48,7 +48,8 @@ class CollisionObject3DSW : public ShapeOwner3DSW {
public:
enum Type {
TYPE_AREA,
- TYPE_BODY
+ TYPE_BODY,
+ TYPE_SOFT_BODY,
};
private:
@@ -129,8 +130,8 @@ public:
_FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; }
_FORCE_INLINE_ real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; }
- _FORCE_INLINE_ Transform get_transform() const { return transform; }
- _FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space3DSW *get_space() const { return space; }
_FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index 651961433c..9d5448dbfa 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -74,9 +74,9 @@ struct _CollectorCallback {
_FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
if (swap) {
- callback(p_point_B, p_point_A, userdata);
+ callback(p_point_B, 0, p_point_A, 0, userdata);
} else {
- callback(p_point_A, p_point_B, userdata);
+ callback(p_point_A, 0, p_point_B, 0, userdata);
}
}
};
@@ -626,7 +626,7 @@ public:
}
}
- _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
+ _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) {
Vector3 axis = p_axis;
if (Math::abs(axis.x) < CMP_EPSILON &&
@@ -662,7 +662,12 @@ public:
//use the smallest depth
if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0
- min_B = -min_B;
+ if (p_directional) {
+ min_B = max_B;
+ axis = -axis;
+ } else {
+ min_B = -min_B;
+ }
}
if (max_B < min_B) {
@@ -680,7 +685,7 @@ public:
return true;
}
- static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+ static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata;
Vector3 axis = (p_point_B - p_point_A);
real_t depth = axis.length();
@@ -1006,23 +1011,31 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// edges and points of B
for (int i = 0; i < 3; i++) {
Vector3 n1 = vertex[i] - p_transform_a.origin;
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
Vector3 axis = n1.cross(n2).cross(n2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1467,15 +1480,20 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// faces of A
for (int i = 0; i < 3; i++) {
Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1486,9 +1504,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 e = vertex[i] - vertex[(i + 1) % 3];
for (int j = 0; j < 3; j++) {
- Vector3 axis = p_transform_a.basis.get_axis(j);
+ Vector3 axis = e.cross(p_transform_a.basis.get_axis(j)).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(e.cross(axis).normalized())) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1508,8 +1529,11 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
(cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
Vector3 axis_ab = support_a - vertex[v];
+ if (axis_ab.dot(normal) < 0.0) {
+ axis_ab *= -1.0;
+ }
- if (!separator.test_axis(axis_ab.normalized())) {
+ if (!separator.test_axis(axis_ab.normalized(), !face_B->backface_collision)) {
return;
}
@@ -1519,7 +1543,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
//a ->b
Vector3 axis_a = p_transform_a.basis.get_axis(i);
- if (!separator.test_axis(axis_ab.cross(axis_a).cross(axis_a).normalized())) {
+ Vector3 axis = axis_ab.cross(axis_a).cross(axis_a).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1544,7 +1573,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 n = (p2 - p1);
- if (!separator.test_axis((point - p2).cross(n).cross(n).normalized())) {
+ Vector3 axis = (point - p2).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1627,10 +1661,55 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p
SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Cylinder B end caps.
+ Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1).normalized();
+ if (!separator.test_axis(cylinder_B_axis)) {
+ return;
+ }
+
+ // Cylinder edge against capsule balls.
+
+ Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1);
+
+ Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5);
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_1).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_2).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ // Cylinder edge against capsule edge.
+
+ Vector3 center_diff = p_transform_b.origin - p_transform_a.origin;
+
+ if (!separator.test_axis(capsule_A_axis.cross(center_diff).cross(capsule_A_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis(cylinder_B_axis.cross(center_diff).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ real_t proj = capsule_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(capsule_A_axis);
+ if (Math::is_zero_approx(proj)) {
+ // Parallel capsule and cylinder axes, handle with specific axes only.
+ // Note: GJKEPA with no margin can lead to degenerate cases in this situation.
+ separator.generate_contacts();
+ return;
+ }
+
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1714,7 +1793,9 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
@@ -1725,13 +1806,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
for (int i = 0; i < 3; i++) {
// edge-cylinder
Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3];
+
Vector3 axis = edge_axis.cross(capsule_axis).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
- if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized())) {
+ Vector3 dir_axis = (p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized();
+ if (dir_axis.dot(normal) < 0.0) {
+ dir_axis *= -1.0;
+ }
+
+ if (!separator.test_axis(dir_axis, !face_B->backface_collision)) {
return;
}
@@ -1740,16 +1830,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
Vector3 n1 = sphere_pos - vertex[i];
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = edge_axis;
axis = n1.cross(n2).cross(n2);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis.normalized())) {
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -1805,7 +1901,7 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1822,7 +1918,7 @@ static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Trans
CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin>::test_contact_points;
// Fallback to generic algorithm to find the best separating axis.
- if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator)) {
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
return;
}
@@ -1846,18 +1942,21 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
p_transform_b.xform(face_B->vertex[2]),
};
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
// Face B normal.
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
Vector3 cyl_axis = p_transform_a.basis.get_axis(1).normalized();
+ if (cyl_axis.dot(normal) < 0.0) {
+ cyl_axis *= -1.0;
+ }
// Cylinder end caps.
- {
- if (!separator.test_axis(cyl_axis)) {
- return;
- }
+ if (!separator.test_axis(cyl_axis, !face_B->backface_collision)) {
+ return;
}
// Edges of B, cylinder lateral surface.
@@ -1868,7 +1967,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
continue;
}
- if (!separator.test_axis(axis.normalized())) {
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -1877,8 +1980,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
for (int i = 0; i < 3; i++) {
const Vector3 &point = vertex[i];
Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1911,8 +2017,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
// Axis is orthogonal both to tangent and edge direction.
Vector3 axis = tangent.cross(edge_dir);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis.normalized())) {
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -2052,7 +2161,9 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
@@ -2060,8 +2171,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int i = 0; i < face_count; i++) {
//Vector3 axis = p_transform_a.xform( faces[i].plane ).normal;
Vector3 axis = p_transform_a.basis.xform(faces[i].plane.normal).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2074,8 +2188,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
Vector3 axis = e1.cross(e2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2087,7 +2204,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 va = p_transform_a.xform(vertices[i]);
for (int j = 0; j < 3; j++) {
- if (!separator.test_axis((va - vertex[j]).normalized())) {
+ Vector3 axis = (va - vertex[j]).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2102,7 +2224,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < 3; j++) {
Vector3 e3 = vertex[j];
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -2116,7 +2243,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < vertex_count; j++) {
Vector3 e3 = p_transform_a.xform(vertices[j]);
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index fd9ea00d92..f655c4626c 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -30,6 +30,7 @@
#include "collision_solver_3d_sw.h"
#include "collision_solver_3d_sat.h"
+#include "soft_body_3d_sw.h"
#include "gjk_epa.h"
@@ -78,9 +79,9 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(supports[i], support_A, p_userdata);
+ p_result_callback(supports[i], 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, supports[i], p_userdata);
+ p_result_callback(support_A, 0, supports[i], 0, p_userdata);
}
}
}
@@ -113,14 +114,148 @@ bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(support_B, support_A, p_userdata);
+ p_result_callback(support_B, 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, support_B, p_userdata);
+ p_result_callback(support_A, 0, support_B, 0, p_userdata);
}
}
return true;
}
+struct _SoftBodyContactCollisionInfo {
+ int node_index = 0;
+ CollisionSolver3DSW::CallbackResult result_callback = nullptr;
+ void *userdata = nullptr;
+ bool swap_result = false;
+ int contact_count = 0;
+};
+
+void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ _SoftBodyContactCollisionInfo &cinfo = *(_SoftBodyContactCollisionInfo *)(p_userdata);
+
+ ++cinfo.contact_count;
+
+ if (cinfo.swap_result) {
+ cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
+ } else {
+ cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata);
+ }
+}
+
+struct _SoftBodyQueryInfo {
+ SoftBody3DSW *soft_body = nullptr;
+ const Shape3DSW *shape_A = nullptr;
+ const Shape3DSW *shape_B = nullptr;
+ Transform transform_A;
+ Transform node_transform;
+ _SoftBodyContactCollisionInfo contact_info;
+#ifdef DEBUG_ENABLED
+ int node_query_count = 0;
+ int convex_query_count = 0;
+#endif
+};
+
+bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *p_userdata) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index);
+
+ Transform transform_B;
+ transform_B.origin = query_cinfo.node_transform.xform(node_position);
+
+ query_cinfo.contact_info.node_index = p_node_index;
+ solve_static(query_cinfo.shape_A, query_cinfo.transform_A, query_cinfo.shape_B, transform_B, soft_body_contact_callback, &query_cinfo.contact_info);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.node_query_count;
+#endif
+
+ // Continue with the query.
+ return false;
+}
+
+void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ query_cinfo.shape_A = p_convex;
+
+ // Calculate AABB for internal soft body query (in world space).
+ AABB shape_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis;
+ axis[i] = 1.0;
+
+ real_t smin, smax;
+ p_convex->project_range(axis, query_cinfo.transform_A, smin, smax);
+
+ shape_aabb.position[i] = smin;
+ shape_aabb.size[i] = smax - smin;
+ }
+
+ shape_aabb.grow_by(query_cinfo.soft_body->get_collision_margin());
+
+ query_cinfo.soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.convex_query_count;
+#endif
+}
+
+bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+ const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B);
+
+ SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body();
+ const Transform &world_to_local = soft_body->get_inv_transform();
+
+ const real_t collision_margin = soft_body->get_collision_margin();
+
+ SphereShape3DSW sphere_shape;
+ sphere_shape.set_data(collision_margin);
+
+ _SoftBodyQueryInfo query_cinfo;
+ query_cinfo.contact_info.result_callback = p_result_callback;
+ query_cinfo.contact_info.userdata = p_userdata;
+ query_cinfo.contact_info.swap_result = p_swap_result;
+ query_cinfo.soft_body = soft_body;
+ query_cinfo.node_transform = p_transform_B * world_to_local;
+ query_cinfo.shape_A = p_shape_A;
+ query_cinfo.transform_A = p_transform_A;
+ query_cinfo.shape_B = &sphere_shape;
+
+ if (p_shape_A->is_concave()) {
+ // In case of concave shape, query convex shapes first.
+ const ConcaveShape3DSW *concave_shape_A = static_cast<const ConcaveShape3DSW *>(p_shape_A);
+
+ AABB soft_body_aabb = soft_body->get_bounds();
+ soft_body_aabb.grow_by(collision_margin);
+
+ // Calculate AABB for internal concave shape query (in local space).
+ AABB local_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis(p_transform_A.basis.get_axis(i));
+ real_t axis_scale = 1.0 / axis.length();
+
+ real_t smin = soft_body_aabb.position[i];
+ real_t smax = smin + soft_body_aabb.size[i];
+
+ smin *= axis_scale;
+ smax *= axis_scale;
+
+ local_aabb.position[i] = smin;
+ local_aabb.size[i] = smax - smin;
+ }
+
+ concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo);
+ } else {
+ AABB shape_aabb = p_transform_A.xform(p_shape_A->get_aabb());
+ shape_aabb.grow_by(collision_margin);
+
+ soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+ }
+
+ return (query_cinfo.contact_info.contact_count > 0);
+}
+
struct _ConcaveCollisionInfo {
const Transform *transform_A;
const Shape3DSW *shape_A;
@@ -215,6 +350,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
if (type_B == PhysicsServer3D::SHAPE_RAY) {
return false;
}
+ if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ return false;
+ }
if (swap) {
return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
@@ -233,6 +371,18 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
return solve_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
+ } else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ // Soft Body / Soft Body not supported.
+ return false;
+ }
+
+ if (swap) {
+ return solve_soft_body(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ } else {
+ return solve_soft_body(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ }
+
} else if (concave_B) {
if (concave_A) {
return false;
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
index 81d87e9773..34ac2c6d3f 100644
--- a/servers/physics_3d/collision_solver_3d_sw.h
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -35,12 +35,16 @@
class CollisionSolver3DSW {
public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
private:
+ static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata);
+ static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
static void concave_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
static void concave_distance_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index aa7c11eec5..1a8c7f704f 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -110,26 +110,60 @@ struct MinkowskiDiff {
Transform transform_A;
Transform transform_B;
+ real_t margin_A = 0.0;
+ real_t margin_B = 0.0;
+
+ Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t);
+
+ void Initialize(const Shape3DSW* shape0, const Transform& wtrs0, const real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, const real_t margin1) {
+ m_shapes[0] = shape0;
+ m_shapes[1] = shape1;
+ transform_A = wtrs0;
+ transform_B = wtrs1;
+ margin_A = margin0;
+ margin_B = margin1;
+
+ if ((margin0 > 0.0) || (margin1 > 0.0)) {
+ get_support = get_support_with_margin;
+ } else {
+ get_support = get_support_without_margin;
+ }
+ }
+
+ static Vector3 get_support_without_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ return p_shape->get_support(p_dir.normalized());
+ }
+
+ static Vector3 get_support_with_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ Vector3 local_dir_norm = p_dir;
+ if (local_dir_norm.length_squared() < CMP_EPSILON2) {
+ local_dir_norm = Vector3(-1.0, -1.0, -1.0);
+ }
+ local_dir_norm.normalize();
+
+ return p_shape->get_support(local_dir_norm) + p_margin * local_dir_norm;
+ }
+
// i wonder how this could be sped up... if it can
- _FORCE_INLINE_ Vector3 Support0 ( const Vector3& d ) const {
- return transform_A.xform( m_shapes[0]->get_support( transform_A.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support0(const Vector3& d) const {
+ return transform_A.xform(get_support(m_shapes[0], transform_A.basis.xform_inv(d), margin_A));
}
- _FORCE_INLINE_ Vector3 Support1 ( const Vector3& d ) const {
- return transform_B.xform( m_shapes[1]->get_support( transform_B.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support1(const Vector3& d) const {
+ return transform_B.xform(get_support(m_shapes[1], transform_B.basis.xform_inv(d), margin_B));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d ) const {
- return ( Support0 ( d )-Support1 ( -d ) );
+ _FORCE_INLINE_ Vector3 Support (const Vector3& d) const {
+ return (Support0(d) - Support1(-d));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d,U index ) const
- {
- if ( index ) {
- return ( Support1 ( d ) );
+ _FORCE_INLINE_ Vector3 Support(const Vector3& d, U index) const {
+ if (index) {
+ return Support1(d);
} else {
- return ( Support0 ( d ) );
-}
+ return Support0(d);
+ }
}
};
@@ -828,22 +862,17 @@ struct GJK
};
//
- static void Initialize( const Shape3DSW* shape0,const Transform& wtrs0,
- const Shape3DSW* shape1,const Transform& wtrs1,
+ static void Initialize( const Shape3DSW* shape0, const Transform& wtrs0, real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, real_t margin1,
sResults& results,
- tShape& shape,
- bool withmargins)
+ tShape& shape)
{
/* Results */
- results.witnesses[0] =
- results.witnesses[1] = Vector3(0,0,0);
+ results.witnesses[0] = Vector3(0,0,0);
+ results.witnesses[1] = Vector3(0,0,0);
results.status = sResults::Separated;
/* Shape */
- shape.m_shapes[0] = shape0;
- shape.m_shapes[1] = shape1;
- shape.transform_A = wtrs0;
- shape.transform_B = wtrs1;
-
+ shape.Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1);
}
@@ -857,13 +886,15 @@ struct GJK
//
bool Distance( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
+ real_t margin1,
const Vector3& guess,
sResults& results)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
if(gjk_status==GJK::eStatus::Valid)
@@ -896,14 +927,16 @@ bool Distance( const Shape3DSW* shape0,
//
bool Penetration( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
- const Vector3& guess,
+ real_t margin1,
+ const Vector3& guess,
sResults& results
)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
switch(gjk_status)
@@ -963,7 +996,7 @@ bool Penetration( const Shape3DSW* shape0,
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) {
r_result_A = res.witnesses[0];
r_result_B = res.witnesses[1];
return true;
@@ -972,15 +1005,15 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_t
return false;
}
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap) {
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {
if (p_result_callback) {
if (p_swap) {
- p_result_callback(res.witnesses[1], res.witnesses[0], p_userdata);
+ p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata);
} else {
- p_result_callback(res.witnesses[0], res.witnesses[1], p_userdata);
+ p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata);
}
}
return true;
diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h
index be3ba4e664..a7e2e1719e 100644
--- a/servers/physics_3d/gjk_epa.h
+++ b/servers/physics_3d/gjk_epa.h
@@ -34,7 +34,7 @@
#include "collision_solver_3d_sw.h"
#include "shape_3d_sw.h"
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false);
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
#endif
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index 6bbef09907..3d0063b0fa 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -611,9 +611,18 @@ uint32_t PhysicsServer3DSW::body_get_collision_mask(RID p_body) const {
void PhysicsServer3DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
+ if (body) {
+ body->set_instance_id(p_id);
+ return;
+ }
+
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ if (soft_body) {
+ soft_body->set_instance_id(p_id);
+ return;
+ }
- body->set_instance_id(p_id);
+ ERR_FAIL_MSG("Invalid ID.");
};
ObjectID PhysicsServer3DSW::body_get_object_instance_id(RID p_body) const {
@@ -893,6 +902,266 @@ PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
return direct_state;
}
+/* SOFT BODY */
+
+RID PhysicsServer3DSW::soft_body_create() {
+ SoftBody3DSW *soft_body = memnew(SoftBody3DSW);
+ RID rid = soft_body_owner.make_rid(soft_body);
+ soft_body->set_self(rid);
+ return rid;
+}
+
+void PhysicsServer3DSW::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->update_rendering_server(p_rendering_server_handler);
+}
+
+void PhysicsServer3DSW::soft_body_set_space(RID p_body, RID p_space) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ Space3DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (soft_body->get_space() == space) {
+ return;
+ }
+
+ soft_body->set_space(space);
+}
+
+RID PhysicsServer3DSW::soft_body_get_space(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, RID());
+
+ Space3DSW *space = soft_body->get_space();
+ if (!space) {
+ return RID();
+ }
+ return space->get_self();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_layer(p_layer);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_layer(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_layer();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_mask(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_mask();
+}
+
+void PhysicsServer3DSW::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->add_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->remove_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ for (int i = 0; i < soft_body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(soft_body->get_exceptions()[i]);
+ }
+}
+
+void PhysicsServer3DSW::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(p_state, p_variant);
+}
+
+Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Variant());
+
+ return soft_body->get_state(p_state);
+}
+
+void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(BODY_STATE_TRANSFORM, p_transform);
+}
+
+void PhysicsServer3DSW::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_ray_pickable(p_enable);
+}
+
+void PhysicsServer3DSW::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_iteration_count(p_simulation_precision);
+}
+
+int PhysicsServer3DSW::soft_body_get_simulation_precision(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_iteration_count();
+}
+
+void PhysicsServer3DSW::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_total_mass(p_total_mass);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_total_mass(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_total_mass();
+}
+
+void PhysicsServer3DSW::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_linear_stiffness(p_stiffness);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_linear_stiffness(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_linear_stiffness();
+}
+
+void PhysicsServer3DSW::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_pressure_coefficient(p_pressure_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_pressure_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_pressure_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_damping_coefficient(p_damping_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_damping_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_damping_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_drag_coefficient(p_drag_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_drag_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_drag_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_mesh(p_mesh);
+}
+
+AABB PhysicsServer3DSW::soft_body_get_bounds(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, AABB());
+
+ return soft_body->get_bounds();
+}
+
+void PhysicsServer3DSW::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_vertex_position(p_point_index, p_global_position);
+}
+
+Vector3 PhysicsServer3DSW::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Vector3());
+
+ return soft_body->get_vertex_position(p_point_index);
+}
+
+void PhysicsServer3DSW::soft_body_remove_all_pinned_points(RID p_body) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->unpin_all_vertices();
+}
+
+void PhysicsServer3DSW::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ if (p_pin) {
+ soft_body->pin_vertex(p_point_index);
+ } else {
+ soft_body->unpin_vertex(p_point_index);
+ }
+}
+
+bool PhysicsServer3DSW::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, false);
+
+ return soft_body->is_vertex_pinned(p_point_index);
+}
+
/* JOINT API */
RID PhysicsServer3DSW::joint_create() {
@@ -1278,7 +1547,13 @@ void PhysicsServer3DSW::free(RID p_rid) {
body_owner.free(p_rid);
memdelete(body);
+ } else if (soft_body_owner.owns(p_rid)) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_rid);
+
+ soft_body->set_space(nullptr);
+ soft_body_owner.free(p_rid);
+ memdelete(soft_body);
} else if (area_owner.owns(p_rid)) {
Area3DSW *area = area_owner.getornull(p_rid);
@@ -1444,7 +1719,7 @@ void PhysicsServer3DSW::_update_shapes() {
}
}
-void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
CollCbkData *cbk = (CollCbkData *)p_userdata;
if (cbk->max == 0) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index afda161fa8..f92652bfad 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -63,6 +63,7 @@ class PhysicsServer3DSW : public PhysicsServer3D {
mutable RID_PtrOwner<Space3DSW, true> space_owner;
mutable RID_PtrOwner<Area3DSW, true> area_owner;
mutable RID_PtrOwner<Body3DSW, true> body_owner;
+ mutable RID_PtrOwner<SoftBody3DSW, true> soft_body_owner;
mutable RID_PtrOwner<Joint3DSW, true> joint_owner;
//void _clear_query(QuerySW *p_query);
@@ -79,7 +80,7 @@ public:
Vector3 *ptr;
};
- static void _shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
virtual RID plane_shape_create() override;
virtual RID ray_shape_create() override;
@@ -252,68 +253,58 @@ public:
/* SOFT BODY */
- virtual RID soft_body_create() override { return RID(); }
+ virtual RID soft_body_create() override;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override {}
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override;
- virtual void soft_body_set_space(RID p_body, RID p_space) override {}
- virtual RID soft_body_get_space(RID p_body) const override { return RID(); }
+ virtual void soft_body_set_space(RID p_body, RID p_space) override;
+ virtual RID soft_body_get_space(RID p_body) const override;
- virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override {}
- virtual uint32_t soft_body_get_collision_layer(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override;
+ virtual uint32_t soft_body_get_collision_layer(RID p_body) const override;
- virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override {}
- virtual uint32_t soft_body_get_collision_mask(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override;
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const override;
- virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {}
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override;
- virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override {}
- virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override { return Variant(); }
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
+ virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override;
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override {}
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override { return Vector3(); }
+ virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
- virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override {}
+ virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override {}
- virtual int soft_body_get_simulation_precision(RID p_body) const override { return 0; }
+ virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override;
+ virtual int soft_body_get_simulation_precision(RID p_body) const override;
- virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override {}
- virtual real_t soft_body_get_total_mass(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override;
+ virtual real_t soft_body_get_total_mass(RID p_body) const override;
- virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_linear_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const override;
- virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_angular_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override;
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_volume_stiffness(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const override;
- virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override {}
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const override;
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override {}
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
- virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override {}
- virtual real_t soft_body_get_damping_coefficient(RID p_body) const override { return 0.; }
+ virtual AABB soft_body_get_bounds(RID p_body) const override;
- virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override {}
- virtual real_t soft_body_get_drag_coefficient(RID p_body) const override { return 0.; }
+ virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override;
- virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override {}
-
- virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override {}
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override { return Vector3(); }
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override { return Vector3(); }
-
- virtual void soft_body_remove_all_pinned_points(RID p_body) override {}
- virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {}
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override { return false; }
+ virtual void soft_body_remove_all_pinned_points(RID p_body) override;
+ virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override;
/* JOINT API */
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index f60e1332d5..49ae60db92 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -273,7 +273,7 @@ public:
FUNCRID(soft_body)
- FUNC2(soft_body_update_rendering_server, RID, class SoftBodyRenderingServerHandler *)
+ FUNC2(soft_body_update_rendering_server, RID, class RenderingServerHandler *)
FUNC2(soft_body_set_space, RID, RID)
FUNC1RC(RID, soft_body_get_space, RID)
@@ -294,7 +294,6 @@ public:
FUNC2RC(Variant, soft_body_get_state, RID, BodyState);
FUNC2(soft_body_set_transform, RID, const Transform &);
- FUNC2RC(Vector3, soft_body_get_vertex_position, RID, int);
FUNC2(soft_body_set_simulation_precision, RID, int);
FUNC1RC(int, soft_body_get_simulation_precision, RID);
@@ -305,18 +304,9 @@ public:
FUNC2(soft_body_set_linear_stiffness, RID, real_t);
FUNC1RC(real_t, soft_body_get_linear_stiffness, RID);
- FUNC2(soft_body_set_angular_stiffness, RID, real_t);
- FUNC1RC(real_t, soft_body_get_angular_stiffness, RID);
-
- FUNC2(soft_body_set_volume_stiffness, RID, real_t);
- FUNC1RC(real_t, soft_body_get_volume_stiffness, RID);
-
FUNC2(soft_body_set_pressure_coefficient, RID, real_t);
FUNC1RC(real_t, soft_body_get_pressure_coefficient, RID);
- FUNC2(soft_body_set_pose_matching_coefficient, RID, real_t);
- FUNC1RC(real_t, soft_body_get_pose_matching_coefficient, RID);
-
FUNC2(soft_body_set_damping_coefficient, RID, real_t);
FUNC1RC(real_t, soft_body_get_damping_coefficient, RID);
@@ -325,9 +315,10 @@ public:
FUNC2(soft_body_set_mesh, RID, const REF &);
+ FUNC1RC(AABB, soft_body_get_bounds, RID);
+
FUNC3(soft_body_move_point, RID, int, const Vector3 &);
FUNC2RC(Vector3, soft_body_get_point_global_position, RID, int);
- FUNC2RC(Vector3, soft_body_get_point_offset, RID, int);
FUNC1(soft_body_remove_all_pinned_points, RID);
FUNC3(soft_body_pin_point, RID, int, bool);
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index 02d0c66215..687a7b288f 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -1134,7 +1134,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_
Vector3 n = p_normal;
/** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+ if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 3;
r_type = FEATURE_FACE;
for (int i = 0; i < 3; i++) {
@@ -1187,7 +1187,11 @@ bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_e
if (c) {
r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
if (r_normal.dot(p_end - p_begin) > 0) {
- r_normal = -r_normal;
+ if (backface_collision) {
+ r_normal = -r_normal;
+ } else {
+ c = false;
+ }
}
}
@@ -1285,30 +1289,24 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par
}
if (bvh->face_index >= 0) {
- Vector3 res;
- Vector3 vertices[3] = {
- p_params->vertices[p_params->faces[bvh->face_index].indices[0]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[1]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[2]]
- };
+ const Face *f = &p_params->faces[bvh->face_index];
+ FaceShape3DSW *face = p_params->face;
+ face->normal = f->normal;
+ face->vertex[0] = p_params->vertices[f->indices[0]];
+ face->vertex[1] = p_params->vertices[f->indices[1]];
+ face->vertex[2] = p_params->vertices[f->indices[2]];
- if (Geometry3D::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
+ Vector3 res;
+ Vector3 normal;
+ if (face->intersect_segment(p_params->from, p_params->to, res, normal)) {
real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
- //TODO, seems segmen/triangle intersection is broken :(
- if (d > 0 && d < p_params->min_d) {
+ if ((d > 0) && (d < p_params->min_d)) {
p_params->min_d = d;
p_params->result = res;
- p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
+ p_params->normal = normal;
p_params->collisions++;
}
}
-
} else {
if (bvh->left >= 0) {
_cull_segment(bvh->left, p_params);
@@ -1329,17 +1327,20 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve
const Vector3 *vr = vertices.ptr();
const BVH *br = bvh.ptr();
+ FaceShape3DSW face;
+ face.backface_collision = backface_collision;
+
_SegmentCullParams params;
params.from = p_begin;
params.to = p_end;
- params.collisions = 0;
params.dir = (p_end - p_begin).normalized();
params.faces = fr;
params.vertices = vr;
params.bvh = br;
- params.min_d = 1e20;
+ params.face = &face;
+
// cull
_cull_segment(0, &params);
@@ -1401,6 +1402,7 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback
const BVH *br = bvh.ptr();
FaceShape3DSW face; // use this to send in the callback
+ face.backface_collision = backface_collision;
_CullParams params;
params.aabb = local_aabb;
@@ -1532,7 +1534,7 @@ void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_ar
memdelete(p_bvh_tree);
}
-void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
+void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) {
int src_face_count = p_faces.size();
if (src_face_count == 0) {
configure(AABB());
@@ -1587,15 +1589,24 @@ void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
int idx = 0;
_fill_bvh(bvh_tree, bvh_arrayw2, idx);
+ backface_collision = p_backface_collision;
+
configure(_aabb); // this type of shape has no margin
}
void ConcavePolygonShape3DSW::set_data(const Variant &p_data) {
- _setup(p_data);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("faces"));
+
+ _setup(d["faces"], d["backface_collision"]);
}
Variant ConcavePolygonShape3DSW::get_data() const {
- return get_faces();
+ Dictionary d;
+ d["faces"] = get_faces();
+ d["backface_collision"] = backface_collision;
+
+ return d;
}
ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index cafe978abb..988e76c699 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -334,34 +334,37 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
struct _CullParams {
AABB aabb;
- Callback callback;
- void *userdata;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- FaceShape3DSW *face;
+ Callback callback = nullptr;
+ void *userdata = nullptr;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
};
struct _SegmentCullParams {
Vector3 from;
Vector3 to;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
Vector3 dir;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
Vector3 result;
Vector3 normal;
- real_t min_d;
- int collisions;
+ real_t min_d = 1e20;
+ int collisions = 0;
};
+ bool backface_collision = false;
+
void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;
void _cull(int p_idx, _CullParams *p_params) const;
void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);
- void _setup(Vector<Vector3> p_faces);
+ void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision);
public:
Vector<Vector3> get_faces() const;
@@ -424,6 +427,7 @@ public:
struct FaceShape3DSW : public Shape3DSW {
Vector3 normal; //cache
Vector3 vertex[3];
+ bool backface_collision = false;
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
new file mode 100644
index 0000000000..f63a470cbe
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -0,0 +1,1221 @@
+/*************************************************************************/
+/* soft_body_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "soft_body_3d_sw.h"
+#include "space_3d_sw.h"
+
+#include "core/math/geometry_3d.h"
+#include "core/templates/map.h"
+
+// Based on Bullet soft body.
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+///btSoftBody implementation by Nathanael Presson
+
+SoftBody3DSW::SoftBody3DSW() :
+ CollisionObject3DSW(TYPE_SOFT_BODY),
+ active_list(this) {
+ _set_static(false);
+}
+
+void SoftBody3DSW::_shapes_changed() {
+}
+
+void SoftBody3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().inverse());
+
+ apply_nodes_transform(get_transform());
+
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ // Not supported.
+ ERR_FAIL_MSG("Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_MSG("Angular velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+}
+
+Variant SoftBody3DSW::get_state(PhysicsServer3D::BodyState p_state) const {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ return get_transform();
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Angular velocity is not supported for Soft bodies.");
+ return Vector3();
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+
+ return Variant();
+}
+
+void SoftBody3DSW::set_space(Space3DSW *p_space) {
+ if (get_space()) {
+ get_space()->soft_body_remove_from_active_list(&active_list);
+
+ deinitialize_shape();
+ }
+
+ _set_space(p_space);
+
+ if (get_space()) {
+ get_space()->soft_body_add_to_active_list(&active_list);
+
+ if (bounds != AABB()) {
+ initialize_shape(true);
+ }
+ }
+}
+
+void SoftBody3DSW::set_mesh(const Ref<Mesh> &p_mesh) {
+ destroy();
+
+ soft_mesh = p_mesh;
+
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ Array arrays = soft_mesh->surface_get_arrays(0);
+ ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX));
+
+ bool success = create_from_trimesh(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
+ if (!success) {
+ destroy();
+ soft_mesh = Ref<Mesh>();
+ }
+}
+
+void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ const uint32_t vertex_count = map_visual_to_physics.size();
+ for (uint32_t i = 0; i < vertex_count; ++i) {
+ const uint32_t node_index = map_visual_to_physics[i];
+ const Node &node = nodes[node_index];
+ const Vector3 &vertex_position = node.x;
+ const Vector3 &vertex_normal = node.n;
+
+ p_rendering_server_handler->set_vertex(i, &vertex_position);
+ p_rendering_server_handler->set_normal(i, &vertex_normal);
+ }
+
+ p_rendering_server_handler->set_aabb(bounds);
+}
+
+void SoftBody3DSW::update_normals() {
+ uint32_t i, ni;
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].n = Vector3();
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+ const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x);
+ face.n[0]->n += n;
+ face.n[1]->n += n;
+ face.n[2]->n += n;
+ face.normal = n;
+ face.normal.normalize();
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ real_t len = node.n.length();
+ if (len > CMP_EPSILON) {
+ node.n /= len;
+ }
+ }
+}
+
+void SoftBody3DSW::update_bounds() {
+ AABB prev_bounds = bounds;
+ prev_bounds.grow_by(collision_margin);
+
+ bounds = AABB();
+
+ const uint32_t nodes_count = nodes.size();
+ if (nodes_count == 0) {
+ deinitialize_shape();
+ return;
+ }
+
+ bool first = true;
+ bool moved = false;
+ for (uint32_t node_index = 0; node_index < nodes_count; ++node_index) {
+ const Node &node = nodes[node_index];
+ if (!prev_bounds.has_point(node.x)) {
+ moved = true;
+ }
+ if (first) {
+ bounds.position = node.x;
+ first = false;
+ } else {
+ bounds.expand_to(node.x);
+ }
+ }
+
+ if (get_space()) {
+ initialize_shape(moved);
+ }
+}
+
+void SoftBody3DSW::update_constants() {
+ reset_link_rest_lengths();
+ update_link_constants();
+ update_area();
+}
+
+void SoftBody3DSW::update_area() {
+ int i, ni;
+
+ // Face area.
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+
+ const Vector3 &x0 = face.n[0]->x;
+ const Vector3 &x1 = face.n[1]->x;
+ const Vector3 &x2 = face.n[2]->x;
+
+ const Vector3 a = x1 - x0;
+ const Vector3 b = x2 - x0;
+ const Vector3 cr = vec3_cross(a, b);
+ face.ra = cr.length();
+ }
+
+ // Node area.
+ LocalVector<int> counts;
+ counts.resize(nodes.size());
+ memset(counts.ptr(), 0, counts.size() * sizeof(int));
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].area = 0.0;
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ for (int j = 0; j < 3; ++j) {
+ const int index = (int)(face.n[j] - &nodes[0]);
+ counts[index]++;
+ face.n[j]->area += Math::abs(face.ra);
+ }
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ if (counts[i] > 0) {
+ nodes[i].area /= (real_t)counts[i];
+ } else {
+ nodes[i].area = 0.0;
+ }
+ }
+}
+
+void SoftBody3DSW::reset_link_rest_lengths() {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.rl = (link.n[0]->x - link.n[1]->x).length();
+ link.c1 = link.rl * link.rl;
+ }
+}
+
+void SoftBody3DSW::update_link_constants() {
+ real_t inv_linear_stiffness = 1.0 / linear_stiffness;
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness;
+ }
+}
+
+void SoftBody3DSW::apply_nodes_transform(const Transform &p_transform) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ uint32_t node_count = nodes.size();
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+
+ node.x = p_transform.xform(node.x);
+ node.q = node.x;
+ node.v = Vector3();
+ node.bv = Vector3();
+
+ AABB node_aabb(node.x, leaf_size);
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ face_tree.clear();
+
+ update_normals();
+ update_bounds();
+ update_constants();
+}
+
+Vector3 SoftBody3DSW::get_vertex_position(int p_index) const {
+ if (soft_mesh.is_null()) {
+ return Vector3();
+ }
+
+ ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());
+ return nodes[node_index].x;
+}
+
+void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.q = node.x;
+ node.x = p_position;
+}
+
+void SoftBody3DSW::pin_vertex(int p_index) {
+ if (is_vertex_pinned(p_index)) {
+ return;
+ }
+
+ pinned_vertices.push_back(p_index);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+}
+
+void SoftBody3DSW::unpin_vertex(int p_index) {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ pinned_vertices.remove(i);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+
+ return;
+ }
+ }
+}
+
+void SoftBody3DSW::unpin_all_vertices() {
+ if (!soft_mesh.is_null()) {
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ uint32_t vertex_index = pinned_vertices[i];
+
+ ERR_CONTINUE(vertex_index >= map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[vertex_index];
+
+ ERR_CONTINUE(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+ }
+
+ pinned_vertices.clear();
+}
+
+bool SoftBody3DSW::is_vertex_pinned(int p_index) const {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint32_t SoftBody3DSW::get_node_count() const {
+ return nodes.size();
+}
+
+real_t SoftBody3DSW::get_node_inv_mass(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), 0.0);
+ return nodes[p_node_index].im;
+}
+
+Vector3 SoftBody3DSW::get_node_position(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].x;
+}
+
+Vector3 SoftBody3DSW::get_node_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].v;
+}
+
+Vector3 SoftBody3DSW::get_node_biased_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].bv;
+}
+
+void SoftBody3DSW::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.v += p_impulse * node.im;
+}
+
+void SoftBody3DSW::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.bv += p_impulse * node.im;
+}
+
+uint32_t SoftBody3DSW::get_face_count() const {
+ return faces.size();
+}
+
+void SoftBody3DSW::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const {
+ ERR_FAIL_COND(p_face_index >= faces.size());
+ const Face &face = faces[p_face_index];
+ r_point_1 = face.n[0]->x;
+ r_point_2 = face.n[1]->x;
+ r_point_3 = face.n[2]->x;
+}
+
+Vector3 SoftBody3DSW::get_face_normal(uint32_t p_face_index) const {
+ ERR_FAIL_COND_V(p_face_index >= faces.size(), Vector3());
+ return faces[p_face_index].normal;
+}
+
+bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) {
+ uint32_t node_count = 0;
+ LocalVector<Vector3> vertices;
+ const int visual_vertex_count(p_vertices.size());
+
+ LocalVector<int> triangles;
+ const uint32_t triangle_count(p_indices.size() / 3);
+ triangles.resize(triangle_count * 3);
+
+ // Merge all overlapping vertices and create a map of physical vertices to visual vertices.
+ {
+ // Process vertices.
+ {
+ uint32_t vertex_count = 0;
+ Map<Vector3, uint32_t> unique_vertices;
+
+ vertices.resize(visual_vertex_count);
+ map_visual_to_physics.resize(visual_vertex_count);
+
+ for (int visual_vertex_index = 0; visual_vertex_index < visual_vertex_count; ++visual_vertex_index) {
+ const Vector3 &vertex = p_vertices[visual_vertex_index];
+
+ Map<Vector3, uint32_t>::Element *e = unique_vertices.find(vertex);
+ uint32_t vertex_id;
+ if (e) {
+ // Already existing.
+ vertex_id = e->value();
+ } else {
+ // Create new one.
+ vertex_id = vertex_count++;
+ unique_vertices[vertex] = vertex_id;
+ vertices[vertex_id] = vertex;
+ }
+
+ map_visual_to_physics[visual_vertex_index] = vertex_id;
+ }
+
+ vertices.resize(vertex_count);
+ }
+
+ // Process triangles.
+ {
+ for (uint32_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) {
+ for (int i = 0; i < 3; ++i) {
+ int visual_index = 3 * triangle_index + i;
+ int physics_index = map_visual_to_physics[p_indices[visual_index]];
+ triangles[visual_index] = physics_index;
+ node_count = MAX((int)node_count, physics_index);
+ }
+ }
+ }
+ }
+
+ ++node_count;
+
+ // Create nodes from vertices.
+ nodes.resize(node_count);
+ real_t inv_node_mass = node_count * inv_total_mass;
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t i = 0; i < node_count; ++i) {
+ Node &node = nodes[i];
+ node.s = vertices[i];
+ node.x = node.s;
+ node.q = node.s;
+ node.im = inv_node_mass;
+
+ AABB node_aabb(node.x, leaf_size);
+ node.leaf = node_tree.insert(node_aabb, &node);
+
+ node.index = i;
+ }
+
+ // Create links and faces from triangles.
+ LocalVector<bool> chks;
+ chks.resize(node_count * node_count);
+ memset(chks.ptr(), 0, chks.size() * sizeof(bool));
+
+ for (uint32_t i = 0; i < triangle_count * 3; i += 3) {
+ const int idx[] = { triangles[i], triangles[i + 1], triangles[i + 2] };
+
+ for (int j = 2, k = 0; k < 3; j = k++) {
+ int chk = idx[k] * node_count + idx[j];
+ if (!chks[chk]) {
+ chks[chk] = true;
+ int inv_chk = idx[j] * node_count + idx[k];
+ chks[inv_chk] = true;
+
+ append_link(idx[j], idx[k]);
+ }
+ }
+
+ append_face(idx[0], idx[1], idx[2]);
+ }
+
+ // Set pinned nodes.
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ int pinned_vertex = pinned_vertices[i];
+
+ ERR_CONTINUE(pinned_vertex >= visual_vertex_count);
+ uint32_t node_index = map_visual_to_physics[pinned_vertex];
+
+ ERR_CONTINUE(node_index >= node_count);
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+
+ generate_bending_constraints(2);
+ reoptimize_link_order();
+
+ update_constants();
+ update_normals();
+ update_bounds();
+
+ return true;
+}
+
+void SoftBody3DSW::generate_bending_constraints(int p_distance) {
+ uint32_t i, j;
+
+ if (p_distance > 1) {
+ // Build graph.
+ const uint32_t n = nodes.size();
+ const unsigned inf = (~(unsigned)0) >> 1;
+ const uint32_t adj_size = n * n;
+ unsigned *adj = memnew_arr(unsigned, adj_size);
+
+#define IDX(_x_, _y_) ((_y_)*n + (_x_))
+ for (j = 0; j < n; ++j) {
+ for (i = 0; i < n; ++i) {
+ int idx_ij = j * n + i;
+ int idx_ji = i * n + j;
+ if (i != j) {
+ adj[idx_ij] = adj[idx_ji] = inf;
+ } else {
+ adj[idx_ij] = adj[idx_ji] = 0;
+ }
+ }
+ }
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ int idx = ib * n + ia;
+ int idx_inv = ia * n + ib;
+ adj[idx] = 1;
+ adj[idx_inv] = 1;
+ }
+
+ // Special optimized case for distance == 2.
+ if (p_distance == 2) {
+ LocalVector<LocalVector<int>> node_links;
+
+ // Build node links.
+ node_links.resize(nodes.size());
+
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ if (node_links[ia].find(ib) == -1) {
+ node_links[ia].push_back(ib);
+ }
+
+ if (node_links[ib].find(ia) == -1) {
+ node_links[ib].push_back(ia);
+ }
+ }
+ for (uint32_t ii = 0; ii < node_links.size(); ii++) {
+ for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) {
+ int k = node_links[ii][jj];
+ for (uint32_t kk = 0; kk < node_links[k].size(); kk++) {
+ int l = node_links[k][kk];
+ if ((int)ii != l) {
+ int idx_ik = k * n + ii;
+ int idx_kj = l * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ ERR_FAIL_COND(sum != 2);
+ int idx_ij = l * n + ii;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = l * n + ii;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // Generic Floyd's algorithm.
+ for (uint32_t k = 0; k < n; ++k) {
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ik = k * n + i;
+ int idx_kj = j * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = j * n + i;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+
+ // Build links.
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] == (unsigned)p_distance) {
+ append_link(i, j);
+ }
+ }
+ }
+ memdelete_arr(adj);
+ }
+}
+
+//===================================================================
+//
+//
+// This function takes in a list of interdependent Links and tries
+// to maximize the distance between calculation
+// of dependent links. This increases the amount of parallelism that can
+// be exploited by out-of-order instruction processors with large but
+// (inevitably) finite instruction windows.
+//
+//===================================================================
+
+// A small structure to track lists of dependent link calculations.
+class LinkDeps {
+public:
+ int value; // A link calculation that is dependent on this one
+ // Positive values = "input A" while negative values = "input B"
+ LinkDeps *next; // Next dependence in the list
+};
+typedef LinkDeps *LinkDepsPtr;
+
+void SoftBody3DSW::reoptimize_link_order() {
+ const int reop_not_dependent = -1;
+ const int reop_node_complete = -2;
+
+ uint32_t i, link_count = links.size(), node_count = nodes.size();
+ Link *lr;
+ int ar, br;
+ Node *node0 = &(nodes[0]);
+ Node *node1 = &(nodes[1]);
+ LinkDepsPtr link_dep;
+ int ready_list_head, ready_list_tail, link_num, link_dep_frees, dep_link;
+
+ // Allocate temporary buffers.
+ int *node_written_at = memnew_arr(int, node_count + 1); // What link calculation produced this node's current values?
+ int *link_dep_A = memnew_arr(int, link_count); // Link calculation input is dependent upon prior calculation #N
+ int *link_dep_B = memnew_arr(int, link_count);
+ int *ready_list = memnew_arr(int, link_count); // List of ready-to-process link calculations (# of links, maximum)
+ LinkDeps *link_dep_free_list = memnew_arr(LinkDeps, 2 * link_count); // Dependent-on-me list elements (2x# of links, maximum)
+ LinkDepsPtr *link_dep_list_starts = memnew_arr(LinkDepsPtr, link_count); // Start nodes of dependent-on-me lists, one for each link
+
+ // Copy the original, unsorted links to a side buffer.
+ Link *link_buffer = memnew_arr(Link, link_count);
+ memcpy(link_buffer, &(links[0]), sizeof(Link) * link_count);
+
+ // Clear out the node setup and ready list.
+ for (i = 0; i < node_count + 1; i++) {
+ node_written_at[i] = reop_not_dependent;
+ }
+ for (i = 0; i < link_count; i++) {
+ link_dep_list_starts[i] = nullptr;
+ }
+ ready_list_head = ready_list_tail = link_dep_frees = 0;
+
+ // Initial link analysis to set up data structures.
+ for (i = 0; i < link_count; i++) {
+ // Note which prior link calculations we are dependent upon & build up dependence lists.
+ lr = &(links[i]);
+ ar = (lr->n[0] - node0) / (node1 - node0);
+ br = (lr->n[1] - node0) / (node1 - node0);
+ if (node_written_at[ar] > reop_not_dependent) {
+ link_dep_A[i] = node_written_at[ar];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = i;
+ link_dep->next = link_dep_list_starts[node_written_at[ar]];
+ link_dep_list_starts[node_written_at[ar]] = link_dep;
+ } else {
+ link_dep_A[i] = reop_not_dependent;
+ }
+ if (node_written_at[br] > reop_not_dependent) {
+ link_dep_B[i] = node_written_at[br];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = -(int)(i + 1);
+ link_dep->next = link_dep_list_starts[node_written_at[br]];
+ link_dep_list_starts[node_written_at[br]] = link_dep;
+ } else {
+ link_dep_B[i] = reop_not_dependent;
+ }
+
+ // Add this link to the initial ready list, if it is not dependent on any other links.
+ if ((link_dep_A[i] == reop_not_dependent) && (link_dep_B[i] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = i;
+ link_dep_A[i] = link_dep_B[i] = reop_node_complete; // Probably not needed now.
+ }
+
+ // Update the nodes to mark which ones are calculated by this link.
+ node_written_at[ar] = node_written_at[br] = i;
+ }
+
+ // Process the ready list and create the sorted list of links:
+ // -- By treating the ready list as a queue, we maximize the distance between any
+ // inter-dependent node calculations.
+ // -- All other (non-related) nodes in the ready list will automatically be inserted
+ // in between each set of inter-dependent link calculations by this loop.
+ i = 0;
+ while (ready_list_head != ready_list_tail) {
+ // Use ready list to select the next link to process.
+ link_num = ready_list[ready_list_head++];
+ // Copy the next-to-calculate link back into the original link array.
+ links[i++] = link_buffer[link_num];
+
+ // Free up any link inputs that are dependent on this one.
+ link_dep = link_dep_list_starts[link_num];
+ while (link_dep) {
+ dep_link = link_dep->value;
+ if (dep_link >= 0) {
+ link_dep_A[dep_link] = reop_not_dependent;
+ } else {
+ dep_link = -dep_link - 1;
+ link_dep_B[dep_link] = reop_not_dependent;
+ }
+ // Add this dependent link calculation to the ready list if *both* inputs are clear.
+ if ((link_dep_A[dep_link] == reop_not_dependent) && (link_dep_B[dep_link] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = dep_link;
+ link_dep_A[dep_link] = link_dep_B[dep_link] = reop_node_complete; // Probably not needed now.
+ }
+ link_dep = link_dep->next;
+ }
+ }
+
+ // Delete the temporary buffers.
+ memdelete_arr(node_written_at);
+ memdelete_arr(link_dep_A);
+ memdelete_arr(link_dep_B);
+ memdelete_arr(ready_list);
+ memdelete_arr(link_dep_free_list);
+ memdelete_arr(link_dep_list_starts);
+ memdelete_arr(link_buffer);
+}
+
+void SoftBody3DSW::append_link(uint32_t p_node1, uint32_t p_node2) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+
+ Link link;
+ link.n[0] = node1;
+ link.n[1] = node2;
+ link.rl = (node1->x - node2->x).length();
+
+ links.push_back(link);
+}
+
+void SoftBody3DSW::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+ if (p_node1 == p_node3) {
+ return;
+ }
+ if (p_node2 == p_node3) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+ Node *node3 = &nodes[p_node3];
+
+ Face face;
+ face.n[0] = node1;
+ face.n[1] = node2;
+ face.n[2] = node3;
+
+ face.index = faces.size();
+
+ faces.push_back(face);
+}
+
+void SoftBody3DSW::set_iteration_count(int p_val) {
+ iteration_count = p_val;
+}
+
+void SoftBody3DSW::set_total_mass(real_t p_val) {
+ ERR_FAIL_COND(p_val < 0.0);
+
+ inv_total_mass = 1.0 / p_val;
+ real_t mass_factor = total_mass * inv_total_mass;
+ total_mass = p_val;
+
+ uint32_t node_count = nodes.size();
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+ node.im *= mass_factor;
+ }
+
+ update_constants();
+}
+
+void SoftBody3DSW::set_collision_margin(real_t p_val) {
+ collision_margin = p_val;
+}
+
+void SoftBody3DSW::set_linear_stiffness(real_t p_val) {
+ linear_stiffness = p_val;
+}
+
+void SoftBody3DSW::set_pressure_coefficient(real_t p_val) {
+ pressure_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_damping_coefficient(real_t p_val) {
+ damping_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_drag_coefficient(real_t p_val) {
+ drag_coefficient = p_val;
+}
+
+void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) {
+ for (uint32_t i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.v += p_velocity;
+ }
+ }
+}
+
+void SoftBody3DSW::apply_forces() {
+ if (pressure_coefficient < CMP_EPSILON) {
+ return;
+ }
+
+ if (nodes.is_empty()) {
+ return;
+ }
+
+ uint32_t i, ni;
+
+ // Calculate volume.
+ real_t volume = 0.0;
+ const Vector3 &org = nodes[0].x;
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));
+ }
+ volume /= 6.0;
+
+ // Apply per node forces.
+ real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.f += node.n * (node.area * ivolumetp);
+ }
+ }
+}
+
+void SoftBody3DSW::predict_motion(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ ERR_FAIL_COND(!get_space());
+
+ Area3DSW *def_area = get_space()->get_default_area();
+ ERR_FAIL_COND(!def_area);
+
+ // Apply forces.
+ Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity();
+ add_velocity(gravity * p_delta);
+ apply_forces();
+
+ // Avoid soft body from 'exploding' so use some upper threshold of maximum motion
+ // that a node can travel per frame.
+ const real_t max_displacement = 1000.0;
+ real_t clamp_delta_v = max_displacement * inv_delta;
+
+ // Integrate.
+ uint32_t i, ni;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.q = node.x;
+ Vector3 delta_v = node.f * node.im * p_delta;
+ for (int c = 0; c < 3; c++) {
+ delta_v[c] = CLAMP(delta_v[c], -clamp_delta_v, clamp_delta_v);
+ }
+ node.v += delta_v;
+ node.x += node.v * p_delta;
+ node.f = Vector3();
+ }
+
+ // Bounds and tree update.
+ update_bounds();
+
+ // Node tree update.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ const Node &node = nodes[i];
+
+ AABB node_aabb(node.x, Vector3());
+ node_aabb.expand_to(node.x + node.v * p_delta);
+ node_aabb.grow_by(collision_margin);
+
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ // Face tree update.
+ if (!face_tree.is_empty()) {
+ update_face_tree(p_delta);
+ }
+
+ // Optimize node tree.
+ node_tree.optimize_incremental(1);
+ face_tree.optimize_incremental(1);
+}
+
+void SoftBody3DSW::solve_constraints(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ uint32_t i, ni;
+
+ for (i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c3 = link.n[1]->q - link.n[0]->q;
+ link.c2 = 1 / (link.c3.length_squared() * link.c0);
+ }
+
+ // Solve velocities.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.x = node.q + node.v * p_delta;
+ }
+
+ // Solve positions.
+ for (int isolve = 0; isolve < iteration_count; ++isolve) {
+ const real_t ti = isolve / (real_t)iteration_count;
+ solve_links(1.0, ti);
+ }
+ const real_t vc = (1.0 - damping_coefficient) * inv_delta;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+
+ node.x += node.bv * p_delta;
+ node.bv = Vector3();
+
+ node.v = (node.x - node.q) * vc;
+
+ node.q = node.x;
+ }
+
+ update_normals();
+}
+
+void SoftBody3DSW::solve_links(real_t kst, real_t ti) {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ if (link.c0 > 0) {
+ Node &node_a = *link.n[0];
+ Node &node_b = *link.n[1];
+ const Vector3 del = node_b.x - node_a.x;
+ const real_t len = del.length_squared();
+ if (link.c1 + len > CMP_EPSILON) {
+ const real_t k = ((link.c1 - len) / (link.c0 * (link.c1 + len))) * kst;
+ node_a.x -= del * (k * node_a.im);
+ node_b.x += del * (k * node_b.im);
+ }
+ }
+ }
+}
+
+struct AABBQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_node_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_aabb(const AABB &p_aabb, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ AABBQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ node_tree.aabb_query(p_aabb, query_result);
+}
+
+struct RayQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_face_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_ray(const Vector3 &p_from, const Vector3 &p_to, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ if (face_tree.is_empty()) {
+ initialize_face_tree();
+ }
+
+ RayQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ face_tree.ray_query(p_from, p_to, query_result);
+}
+
+void SoftBody3DSW::initialize_face_tree() {
+ face_tree.clear();
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ Face &face = faces[i];
+
+ AABB face_aabb;
+
+ face_aabb.position = face.n[0]->x;
+ face_aabb.expand_to(face.n[1]->x);
+ face_aabb.expand_to(face.n[2]->x);
+
+ face_aabb.grow_by(collision_margin);
+
+ face.leaf = face_tree.insert(face_aabb, &face);
+ }
+}
+
+void SoftBody3DSW::update_face_tree(real_t p_delta) {
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ const Face &face = faces[i];
+
+ AABB face_aabb;
+
+ const Node *node0 = face.n[0];
+ face_aabb.position = node0->x;
+ face_aabb.expand_to(node0->x + node0->v * p_delta);
+
+ const Node *node1 = face.n[1];
+ face_aabb.expand_to(node1->x);
+ face_aabb.expand_to(node1->x + node1->v * p_delta);
+
+ const Node *node2 = face.n[2];
+ face_aabb.expand_to(node2->x);
+ face_aabb.expand_to(node2->x + node2->v * p_delta);
+
+ face_aabb.grow_by(collision_margin);
+
+ face_tree.update(face.leaf, face_aabb);
+ }
+}
+
+void SoftBody3DSW::initialize_shape(bool p_force_move) {
+ if (get_shape_count() == 0) {
+ SoftBodyShape3DSW *soft_body_shape = memnew(SoftBodyShape3DSW(this));
+ add_shape(soft_body_shape);
+ } else if (p_force_move) {
+ SoftBodyShape3DSW *soft_body_shape = static_cast<SoftBodyShape3DSW *>(get_shape(0));
+ soft_body_shape->update_bounds();
+ }
+}
+
+void SoftBody3DSW::deinitialize_shape() {
+ if (get_shape_count() > 0) {
+ Shape3DSW *shape = get_shape(0);
+ remove_shape(shape);
+ memdelete(shape);
+ }
+}
+
+void SoftBody3DSW::destroy() {
+ map_visual_to_physics.clear();
+
+ node_tree.clear();
+ face_tree.clear();
+
+ nodes.clear();
+ links.clear();
+ faces.clear();
+
+ bounds = AABB();
+ deinitialize_shape();
+}
+
+void SoftBodyShape3DSW::update_bounds() {
+ ERR_FAIL_COND(!soft_body);
+
+ AABB collision_aabb = soft_body->get_bounds();
+ collision_aabb.grow_by(soft_body->get_collision_margin());
+ configure(collision_aabb);
+}
+
+SoftBodyShape3DSW::SoftBodyShape3DSW(SoftBody3DSW *p_soft_body) {
+ soft_body = p_soft_body;
+ update_bounds();
+}
+
+struct _SoftBodyIntersectSegmentInfo {
+ const SoftBody3DSW *soft_body = nullptr;
+ Vector3 from;
+ Vector3 dir;
+ Vector3 hit_position;
+ uint32_t hit_face_index = -1;
+ real_t hit_dist_sq = Math_INF;
+
+ static bool process_hit(uint32_t p_face_index, void *p_userdata) {
+ _SoftBodyIntersectSegmentInfo &query_info = *(_SoftBodyIntersectSegmentInfo *)(p_userdata);
+
+ Vector3 points[3];
+ query_info.soft_body->get_face_points(p_face_index, points[0], points[1], points[2]);
+
+ Vector3 result;
+ if (Geometry3D::ray_intersects_triangle(query_info.from, query_info.dir, points[0], points[1], points[2], &result)) {
+ real_t dist_sq = query_info.from.distance_squared_to(result);
+ if (dist_sq < query_info.hit_dist_sq) {
+ query_info.hit_dist_sq = dist_sq;
+ query_info.hit_position = result;
+ query_info.hit_face_index = p_face_index;
+ }
+ }
+
+ // Continue with the query.
+ return false;
+ }
+};
+
+bool SoftBodyShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+ _SoftBodyIntersectSegmentInfo query_info;
+ query_info.soft_body = soft_body;
+ query_info.from = p_begin;
+ query_info.dir = (p_end - p_begin).normalized();
+
+ soft_body->query_ray(p_begin, p_end, _SoftBodyIntersectSegmentInfo::process_hit, &query_info);
+
+ if (query_info.hit_dist_sq != Math_INF) {
+ r_result = query_info.hit_position;
+ r_normal = soft_body->get_face_normal(query_info.hit_face_index);
+ return true;
+ }
+
+ return false;
+}
+
+bool SoftBodyShape3DSW::intersect_point(const Vector3 &p_point) const {
+ return false;
+}
+
+Vector3 SoftBodyShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+ ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies.");
+}
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
new file mode 100644
index 0000000000..6c0451ff45
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -0,0 +1,247 @@
+/*************************************************************************/
+/* soft_body_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 SOFT_BODY_3D_SW_H
+#define SOFT_BODY_3D_SW_H
+
+#include "collision_object_3d_sw.h"
+
+#include "core/math/aabb.h"
+#include "core/math/dynamic_bvh.h"
+#include "core/math/vector3.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/set.h"
+#include "core/templates/vset.h"
+#include "scene/resources/mesh.h"
+
+class Constraint3DSW;
+
+class SoftBody3DSW : public CollisionObject3DSW {
+ Ref<Mesh> soft_mesh;
+
+ struct Node {
+ Vector3 s; // Source position
+ Vector3 x; // Position
+ Vector3 q; // Previous step position/Test position
+ Vector3 f; // Force accumulator
+ Vector3 v; // Velocity
+ Vector3 bv; // Biased Velocity
+ Vector3 n; // Normal
+ real_t area = 0.0; // Area
+ real_t im = 0.0; // 1/mass
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ struct Link {
+ Vector3 c3; // gradient
+ Node *n[2] = { nullptr, nullptr }; // Node pointers
+ real_t rl = 0.0; // Rest length
+ real_t c0 = 0.0; // (ima+imb)*kLST
+ real_t c1 = 0.0; // rl^2
+ real_t c2 = 0.0; // |gradient|^2/c0
+ };
+
+ struct Face {
+ Node *n[3] = { nullptr, nullptr, nullptr }; // Node pointers
+ Vector3 normal; // Normal
+ real_t ra = 0.0; // Rest area
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ LocalVector<Node> nodes;
+ LocalVector<Link> links;
+ LocalVector<Face> faces;
+
+ DynamicBVH node_tree;
+ DynamicBVH face_tree;
+
+ LocalVector<uint32_t> map_visual_to_physics;
+
+ AABB bounds;
+
+ real_t collision_margin = 0.05;
+
+ real_t total_mass = 1.0;
+ real_t inv_total_mass = 1.0;
+
+ int iteration_count = 5;
+ real_t linear_stiffness = 0.5; // [0,1]
+ real_t pressure_coefficient = 0.0; // [-inf,+inf]
+ real_t damping_coefficient = 0.01; // [0,1]
+ real_t drag_coefficient = 0.0; // [0,1]
+ LocalVector<int> pinned_vertices;
+
+ SelfList<SoftBody3DSW> active_list;
+
+ Set<Constraint3DSW *> constraints;
+
+ VSet<RID> exceptions;
+
+public:
+ SoftBody3DSW();
+
+ const AABB &get_bounds() const { return bounds; }
+
+ void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer3D::BodyState p_state) const;
+
+ _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint) { constraints.insert(p_constraint); }
+ _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraints.erase(p_constraint); }
+ _FORCE_INLINE_ const Set<Constraint3DSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
+
+ _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); }
+ _FORCE_INLINE_ void remove_exception(const RID &p_exception) { exceptions.erase(p_exception); }
+ _FORCE_INLINE_ bool has_exception(const RID &p_exception) const { return exceptions.has(p_exception); }
+ _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; }
+
+ virtual void set_space(Space3DSW *p_space);
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+
+ void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
+
+ Vector3 get_vertex_position(int p_index) const;
+ void set_vertex_position(int p_index, const Vector3 &p_position);
+
+ void pin_vertex(int p_index);
+ void unpin_vertex(int p_index);
+ void unpin_all_vertices();
+ bool is_vertex_pinned(int p_index) const;
+
+ uint32_t get_node_count() const;
+ real_t get_node_inv_mass(uint32_t p_node_index) const;
+ Vector3 get_node_position(uint32_t p_node_index) const;
+ Vector3 get_node_velocity(uint32_t p_node_index) const;
+ Vector3 get_node_biased_velocity(uint32_t p_node_index) const;
+ void apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+ void apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+
+ uint32_t get_face_count() const;
+ void get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const;
+ Vector3 get_face_normal(uint32_t p_face_index) const;
+
+ void set_iteration_count(int p_val);
+ _FORCE_INLINE_ real_t get_iteration_count() const { return iteration_count; }
+
+ void set_total_mass(real_t p_val);
+ _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; }
+ _FORCE_INLINE_ real_t get_total_inv_mass() const { return inv_total_mass; }
+
+ void set_collision_margin(real_t p_val);
+ _FORCE_INLINE_ real_t get_collision_margin() const { return collision_margin; }
+
+ void set_linear_stiffness(real_t p_val);
+ _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
+
+ void set_pressure_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
+
+ void set_damping_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
+
+ void set_drag_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
+
+ void predict_motion(real_t p_delta);
+ void solve_constraints(real_t p_delta);
+
+ _FORCE_INLINE_ uint32_t get_node_index(void *p_node) const { return ((Node *)p_node)->index; }
+ _FORCE_INLINE_ uint32_t get_face_index(void *p_face) const { return ((Face *)p_face)->index; }
+
+ // Return true to stop the query.
+ // p_index is the node index for AABB query, face index for Ray query.
+ typedef bool (*QueryResultCallback)(uint32_t p_index, void *p_userdata);
+
+ void query_aabb(const AABB &p_aabb, QueryResultCallback p_result_callback, void *p_userdata);
+ void query_ray(const Vector3 &p_from, const Vector3 &p_to, QueryResultCallback p_result_callback, void *p_userdata);
+
+protected:
+ virtual void _shapes_changed();
+
+private:
+ void update_normals();
+ void update_bounds();
+ void update_constants();
+ void update_area();
+ void reset_link_rest_lengths();
+ void update_link_constants();
+
+ void apply_nodes_transform(const Transform &p_transform);
+
+ void add_velocity(const Vector3 &p_velocity);
+
+ void apply_forces();
+
+ bool create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices);
+ void generate_bending_constraints(int p_distance);
+ void reoptimize_link_order();
+ void append_link(uint32_t p_node1, uint32_t p_node2);
+ void append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3);
+
+ void solve_links(real_t kst, real_t ti);
+
+ void initialize_face_tree();
+ void update_face_tree(real_t p_delta);
+
+ void initialize_shape(bool p_force_move = true);
+ void deinitialize_shape();
+
+ void destroy();
+};
+
+class SoftBodyShape3DSW : public Shape3DSW {
+ SoftBody3DSW *soft_body = nullptr;
+
+public:
+ SoftBody3DSW *get_soft_body() const { return soft_body; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; }
+ virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
+ virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
+
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
+ virtual bool intersect_point(const Vector3 &p_point) const;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); }
+
+ virtual void set_data(const Variant &p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ void update_bounds();
+
+ SoftBodyShape3DSW(SoftBody3DSW *p_soft_body);
+ ~SoftBodyShape3DSW() {}
+};
+
+#endif // SOFT_BODY_3D_SW_H
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index c8741dc930..2df824b320 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -47,6 +47,10 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint
return false;
}
+ if (p_object->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY && !p_collide_with_bodies) {
+ return false;
+ }
+
return true;
}
@@ -332,7 +336,8 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
best_first = false;
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(col_obj);
- r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
+ Vector3 rel_vec = closest_B - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -407,7 +412,7 @@ struct _RestCallbackData {
real_t min_allowed_depth;
};
-static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
_RestCallbackData *rd = (_RestCallbackData *)p_userdata;
Vector3 contact_rel = p_point_B - p_point_A;
@@ -478,8 +483,8 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
r_info->rid = rcd.best_object->get_self();
if (rcd.best_object->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- r_info->linear_velocity = body->get_linear_velocity() +
- (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
} else {
r_info->linear_velocity = Vector3();
@@ -544,6 +549,8 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
keep = false;
} else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_AREA) {
keep = false;
+ } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ keep = false;
} else if ((static_cast<Body3DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
keep = false;
} else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
@@ -684,10 +691,8 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
//result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
Body3DSW *body = (Body3DSW *)col_obj;
-
- Vector3 rel_vec = b - body->get_transform().get_origin();
- //result.collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rel_vec); // * mPos);
+ Vector3 rel_vec = b - (body->get_transform().origin + body->get_center_of_mass());
+ result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -1009,9 +1014,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- //Vector3 rel_vec = r_result->collision_point - body->get_transform().get_origin();
- // r_result->collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
r_result->motion = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
@@ -1054,14 +1059,23 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll
Area3DSW *area_b = static_cast<Area3DSW *>(B);
Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A));
return area2_pair;
+ } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ // Area/Soft Body, not supported.
} else {
Body3DSW *body = static_cast<Body3DSW *>(B);
AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A));
return area_pair;
}
+ } else if (type_A == CollisionObject3DSW::TYPE_BODY) {
+ if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ BodySoftBodyPair3DSW *soft_pair = memnew(BodySoftBodyPair3DSW((Body3DSW *)A, p_subindex_A, (SoftBody3DSW *)B));
+ return soft_pair;
+ } else {
+ BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
+ return b;
+ }
} else {
- BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
- return b;
+ // Soft Body/Soft Body, not supported.
}
return nullptr;
@@ -1144,6 +1158,18 @@ const SelfList<Area3DSW>::List &Space3DSW::get_moved_area_list() const {
return area_moved_list;
}
+const SelfList<SoftBody3DSW>::List &Space3DSW::get_active_soft_body_list() const {
+ return active_soft_body_list;
+}
+
+void Space3DSW::soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.add(p_soft_body);
+}
+
+void Space3DSW::soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.remove(p_soft_body);
+}
+
void Space3DSW::call_queries() {
while (state_query_list.first()) {
Body3DSW *b = state_query_list.first()->self();
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index eed3d86a72..3a8f452e54 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -40,6 +40,7 @@
#include "core/config/project_settings.h"
#include "core/templates/hash_map.h"
#include "core/typedefs.h"
+#include "soft_body_3d_sw.h"
class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D {
GDCLASS(PhysicsDirectSpaceState3DSW, PhysicsDirectSpaceState3D);
@@ -82,6 +83,7 @@ private:
SelfList<Body3DSW>::List state_query_list;
SelfList<Area3DSW>::List monitor_query_list;
SelfList<Area3DSW>::List area_moved_list;
+ SelfList<SoftBody3DSW>::List active_soft_body_list;
static void *_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self);
static void _broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self);
@@ -145,6 +147,10 @@ public:
void area_remove_from_moved_list(SelfList<Area3DSW> *p_area);
const SelfList<Area3DSW>::List &get_moved_area_list() const;
+ const SelfList<SoftBody3DSW>::List &get_active_soft_body_list() const;
+ void soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+ void soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+
BroadPhase3DSW *get_broadphase();
void add_object(CollisionObject3DSW *p_object);
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index d9370de6a3..9a73e11562 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -146,6 +146,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list();
+ const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list();
+
/* INTEGRATE FORCES */
uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
@@ -160,6 +162,15 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
active_count++;
}
+ /* UPDATE SOFT BODY MOTION */
+
+ const SelfList<SoftBody3DSW> *sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->predict_motion(p_delta);
+ sb = sb->next();
+ active_count++;
+ }
+
p_space->set_active_objects(active_count);
{ //profile
@@ -214,6 +225,20 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
}
+ sb = soft_body_list->first();
+ while (sb) {
+ for (const Set<Constraint3DSW *>::Element *E = sb->self()->get_constraints().front(); E; E = E->next()) {
+ Constraint3DSW *c = E->get();
+ if (c->get_island_step() == _step)
+ continue;
+ c->set_island_step(_step);
+ c->set_island_next(NULL);
+ c->set_island_list_next(constraint_island_list);
+ constraint_island_list = c;
+ }
+ sb = sb->next();
+ }
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
@@ -272,6 +297,14 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
}
}
+ /* UPDATE SOFT BODY CONSTRAINTS */
+
+ sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->solve_constraints(p_delta);
+ sb = sb->next();
+ }
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index af25029f04..586845de99 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -556,6 +556,10 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
+ /* SOFT BODY API */
+
+ ClassDB::bind_method(D_METHOD("soft_body_get_bounds", "body"), &PhysicsServer3D::soft_body_get_bounds);
+
/* JOINT API */
ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer3D::joint_create);
@@ -693,6 +697,7 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);
+ BIND_ENUM_CONSTANT(SHAPE_SOFT_BODY);
BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index e16857192c..69f5c1c0ad 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -216,6 +216,15 @@ public:
PhysicsShapeQueryResult3D();
};
+class RenderingServerHandler {
+public:
+ virtual void set_vertex(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_normal(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_aabb(const AABB &p_aabb) = 0;
+
+ virtual ~RenderingServerHandler() {}
+};
+
class PhysicsServer3D : public Object {
GDCLASS(PhysicsServer3D, Object);
@@ -237,6 +246,7 @@ public:
SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
SHAPE_CONCAVE_POLYGON, ///< vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
SHAPE_HEIGHTMAP, ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
+ SHAPE_SOFT_BODY, ///< Used internally, can't be created from the physics server.
SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
};
@@ -522,13 +532,15 @@ public:
virtual RID soft_body_create() = 0;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) = 0;
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) = 0;
virtual void soft_body_set_space(RID p_body, RID p_space) = 0;
virtual RID soft_body_get_space(RID p_body) const = 0;
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0;
+ virtual AABB soft_body_get_bounds(RID p_body) const = 0;
+
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
virtual uint32_t soft_body_get_collision_layer(RID p_body) const = 0;
@@ -543,7 +555,6 @@ public:
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0;
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0;
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -556,18 +567,9 @@ public:
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0;
virtual real_t soft_body_get_linear_stiffness(RID p_body) const = 0;
- virtual void soft_body_set_angular_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_angular_stiffness(RID p_body) const = 0;
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_volume_stiffness(RID p_body) const = 0;
-
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0;
virtual real_t soft_body_get_pressure_coefficient(RID p_body) const = 0;
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0;
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) const = 0;
-
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0;
virtual real_t soft_body_get_damping_coefficient(RID p_body) const = 0;
@@ -577,8 +579,6 @@ public:
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0;
virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const = 0;
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0;
-
virtual void soft_body_remove_all_pinned_points(RID p_body) = 0;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0;
virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const = 0;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 2a34049675..ba5ace8f31 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -5121,6 +5121,7 @@ void RendererStorageRD::particles_collision_height_field_update(RID p_particles_
void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
if (particles_collision->heightfield_resolution == p_resolution) {
return;
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index 0f85e3fa30..fc513d3fb9 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -3,46 +3,15 @@
Import("env")
if "RD_GLSL" in env["BUILDERS"]:
- env.RD_GLSL("canvas.glsl")
- env.RD_GLSL("canvas_occlusion.glsl")
- env.RD_GLSL("canvas_sdf.glsl")
- env.RD_GLSL("copy.glsl")
- env.RD_GLSL("copy_to_fb.glsl")
- env.RD_GLSL("cubemap_roughness.glsl")
- env.RD_GLSL("cubemap_downsampler.glsl")
- env.RD_GLSL("cubemap_filter.glsl")
- env.RD_GLSL("scene_forward_clustered.glsl")
- env.RD_GLSL("sky.glsl")
- env.RD_GLSL("tonemap.glsl")
- env.RD_GLSL("cube_to_dp.glsl")
- env.RD_GLSL("giprobe.glsl")
- env.RD_GLSL("giprobe_debug.glsl")
- env.RD_GLSL("giprobe_sdf.glsl")
- env.RD_GLSL("luminance_reduce.glsl")
- env.RD_GLSL("bokeh_dof.glsl")
- env.RD_GLSL("ssao.glsl")
- env.RD_GLSL("ssao_downsample.glsl")
- env.RD_GLSL("ssao_importance_map.glsl")
- env.RD_GLSL("ssao_blur.glsl")
- env.RD_GLSL("ssao_interleave.glsl")
- env.RD_GLSL("roughness_limiter.glsl")
- env.RD_GLSL("screen_space_reflection.glsl")
- env.RD_GLSL("screen_space_reflection_filter.glsl")
- env.RD_GLSL("screen_space_reflection_scale.glsl")
- env.RD_GLSL("subsurface_scattering.glsl")
- env.RD_GLSL("specular_merge.glsl")
- env.RD_GLSL("gi.glsl")
- env.RD_GLSL("resolve.glsl")
- env.RD_GLSL("sdfgi_preprocess.glsl")
- env.RD_GLSL("sdfgi_integrate.glsl")
- env.RD_GLSL("sdfgi_direct_light.glsl")
- env.RD_GLSL("sdfgi_debug.glsl")
- env.RD_GLSL("sdfgi_debug_probes.glsl")
- env.RD_GLSL("volumetric_fog.glsl")
- env.RD_GLSL("particles.glsl")
- env.RD_GLSL("particles_copy.glsl")
- env.RD_GLSL("sort.glsl")
- env.RD_GLSL("skeleton.glsl")
- env.RD_GLSL("cluster_render.glsl")
- env.RD_GLSL("cluster_store.glsl")
- env.RD_GLSL("cluster_debug.glsl")
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files)
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index c6be07a3de..e82d5cc3f8 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -233,7 +233,7 @@ public:
FUNC2(shader_set_code, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
- FUNC2C(shader_get_param_list, RID, List<PropertyInfo> *)
+ FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp
index 74afbad9d1..bb324d8ffe 100644
--- a/tests/test_physics_3d.cpp
+++ b/tests/test_physics_3d.cpp
@@ -187,8 +187,10 @@ protected:
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON);
- ps->shape_set_data(trimesh_shape, p_faces);
- p_faces = ps->shape_get_data(trimesh_shape); // optimized one
+ Dictionary trimesh_params;
+ trimesh_params["faces"] = p_faces;
+ trimesh_params["backface_collision"] = false;
+ ps->shape_set_data(trimesh_shape, trimesh_params);
Vector<Vector3> normals; // for drawing
for (int i = 0; i < p_faces.size() / 3; i++) {
Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]);
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 3803e87fea..b05f074bd6 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -174,7 +174,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 2.7.4 (7236c7e29cef1c2d76c7a284c5081ff4d3aa1127, 2020)
+- Version: 2.8.0 (03538e872a0610a65fad692b33d3646f387cf578, 2021)
- License: MIT
Files extracted from upstream source:
@@ -324,7 +324,7 @@ changes are marked with `// -- GODOT --` comments.
## mbedtls
- Upstream: https://tls.mbed.org/
-- Version: 2.16.9 (3fac0bae4a50113989b3d015cd2d948f51a6d9ac, 2020)
+- Version: 2.16.10 (d61fa61bef06b64132e3490543c81b8ee40fbee3, 2021)
- License: Apache 2.0
File extracted from upstream release tarball:
@@ -355,18 +355,20 @@ Files extracted from upstream repository:
## miniupnpc
-- Upstream: https://github.com/miniupnp/miniupnp/tree/master/miniupnpc
-- Version: git (44366328661826603982d1e0d7ebb4062c5f2bfc, 2020)
+- Upstream: https://github.com/miniupnp/miniupnp
+- Version: 2.2.2 (81029a860baf1f727903e5b85307903b3f40cbc8, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
- All `*.c` and `*.h` files from `miniupnpc` to `thirdparty/miniupnpc/miniupnpc`
-- Remove `test*`, `minihttptestserver.c` and `wingenminiupnpcstrings.c`
+- Remove the following test or sample files:
+ `listdevices.c minihttptestserver.c miniupnpcmodule.c upnpc.c upnperrors.* test* wingenminiupnpcstrings.c`
+- `LICENSE`
-The patch `windows_fix.diff` is applied to `minissdpc.c` to fix an upstream issue.
-The only modified file is miniupnpcstrings.h, which was created for Godot
-(it is usually autogenerated by cmake).
+The only modified file is `miniupnpcstrings.h`, which was created for Godot
+(it is usually autogenerated by cmake). Bump the version number for miniupnpc in that
+file when upgrading.
## minizip
diff --git a/thirdparty/harfbuzz/NEWS b/thirdparty/harfbuzz/NEWS
index f09c2fafd1..321c550188 100644
--- a/thirdparty/harfbuzz/NEWS
+++ b/thirdparty/harfbuzz/NEWS
@@ -1,3 +1,18 @@
+Overview of changes leading to 2.8.0
+Tuesday, March 16, 2021
+====================================
+- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine.
+ Previously these were shaped using the generalized Arabic shaper. (David Corbett)
+- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett)
+- Update language tags. (David Corbett)
+- Variations: reduce error: do not round each interpolated delta. (Just van Rossum)
+- Documentation improvements. (Khaled Hosny, Nathan Willis)
+- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu)
+- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad)
+- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad)
+- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad)
+
+
Overview of changes leading to 2.7.4
Sunday, December 27, 2020
====================================
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
index 75d523f5fc..98ed20d8eb 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
@@ -510,7 +510,7 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses))
- klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
+ klass = StateTable::CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -576,7 +576,7 @@ struct StateTable
if (unlikely (stop > states))
return_trace (false);
for (const HBUSHORT *p = states; stop < p; p--)
- num_entries = hb_max (num_entries, *(p - 1) + 1);
+ num_entries = hb_max (num_entries, *(p - 1) + 1u);
state_neg = min_state;
}
}
@@ -597,7 +597,7 @@ struct StateTable
if (unlikely (stop < states))
return_trace (false);
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
- num_entries = hb_max (num_entries, *p + 1);
+ num_entries = hb_max (num_entries, *p + 1u);
state_pos = max_state + 1;
}
}
@@ -729,7 +729,10 @@ struct ExtendedTypes
template <typename Types, typename EntryData>
struct StateTableDriver
{
- StateTableDriver (const StateTable<Types, EntryData> &machine_,
+ using StateTableT = StateTable<Types, EntryData>;
+ using EntryT = Entry<EntryData>;
+
+ StateTableDriver (const StateTableT &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
@@ -742,59 +745,101 @@ struct StateTableDriver
if (!c->in_place)
buffer->clear_output ();
- int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
+ int state = StateTableT::STATE_START_OF_TEXT;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
- (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
+ (unsigned) StateTableT::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
- const Entry<EntryData> &entry = machine.get_entry (state, klass);
+ const EntryT &entry = machine.get_entry (state, klass);
+ const int next_state = machine.new_state (entry.newState);
- /* Unsafe-to-break before this if not in state 0, as things might
- * go differently if we start from state 0 here.
+ /* Conditions under which it's guaranteed safe-to-break before current glyph:
*
- * Ugh. The indexing here is ugly... */
- if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
- {
- /* If there's no action and we're just epsilon-transitioning to state 0,
- * safe to break. */
- if (c->is_actionable (this, entry) ||
- !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
- entry.flags == context_t::DontAdvance))
- buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
- }
-
- /* Unsafe-to-break if end-of-text would kick in here. */
- if (buffer->idx + 2 <= buffer->len)
- {
- const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
- if (c->is_actionable (this, end_entry))
- buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
- }
+ * 1. There was no action in this transition; and
+ *
+ * 2. If we break before current glyph, the results will be the same. That
+ * is guaranteed if:
+ *
+ * 2a. We were already in start-of-text state; or
+ *
+ * 2b. We are epsilon-transitioning to start-of-text state; or
+ *
+ * 2c. Starting from start-of-text state seeing current glyph:
+ *
+ * 2c'. There won't be any actions; and
+ *
+ * 2c". We would end up in the same state that we were going to end up
+ * in now, including whether epsilon-transitioning.
+ *
+ * and
+ *
+ * 3. If we break before current glyph, there won't be any end-of-text action
+ * after previous glyph.
+ *
+ * This triples the transitions we need to look up, but is worth returning
+ * granular unsafe-to-break results. See eg.:
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/2860
+ */
+ const EntryT *wouldbe_entry;
+ bool safe_to_break =
+ /* 1. */
+ !c->is_actionable (this, entry)
+ &&
+ /* 2. */
+ (
+ /* 2a. */
+ state == StateTableT::STATE_START_OF_TEXT
+ ||
+ /* 2b. */
+ (
+ (entry.flags & context_t::DontAdvance) &&
+ next_state == StateTableT::STATE_START_OF_TEXT
+ )
+ ||
+ /* 2c. */
+ (
+ wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
+ ,
+ /* 2c'. */
+ !c->is_actionable (this, *wouldbe_entry)
+ &&
+ /* 2c". */
+ (
+ next_state == machine.new_state (wouldbe_entry->newState)
+ &&
+ (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
+ )
+ )
+ )
+ &&
+ /* 3. */
+ !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
+ ;
+
+ if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
+ buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (this, entry);
- state = machine.new_state (entry.newState);
+ state = next_state;
DEBUG_MSG (APPLY, nullptr, "s%d", state);
- if (buffer->idx == buffer->len)
+ if (buffer->idx == buffer->len || unlikely (!buffer->successful))
break;
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
if (!c->in_place)
- {
- for (; buffer->successful && buffer->idx < buffer->len;)
- buffer->next_glyph ();
buffer->swap_buffers ();
- }
}
public:
- const StateTable<Types, EntryData> &machine;
+ const StateTableT &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
index 04027a61be..e3bc268d26 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -337,9 +337,9 @@ struct ContextualSubtable
const EntryData &data = entries[i].data;
if (data.markIndex != 0xFFFF)
- num_lookups = hb_max (num_lookups, 1 + data.markIndex);
+ num_lookups = hb_max (num_lookups, 1u + data.markIndex);
if (data.currentIndex != 0xFFFF)
- num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
+ num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
}
return_trace (substitutionTables.sanitize (c, this, num_lookups));
@@ -499,7 +499,7 @@ struct LigatureSubtable
}
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
- buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
+ if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
action = *actionData;
@@ -525,25 +525,25 @@ struct LigatureSubtable
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
- buffer->replace_glyph (lig);
+ if (unlikely (!buffer->replace_glyph (lig))) return;
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
/* Now go and delete all subsequent components. */
while (match_length - 1u > cursor)
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
- buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
- buffer->replace_glyph (DELETED_GLYPH);
+ if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+ if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
- buffer->move_to (lig_end);
+ if (unlikely (!buffer->move_to (lig_end))) return;
buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
}
actionData++;
}
while (!(action & LigActionLast));
- buffer->move_to (end);
+ if (unlikely (!buffer->move_to (end))) return;
}
}
@@ -733,17 +733,16 @@ struct InsertionSubtable
bool before = flags & MarkedInsertBefore;
unsigned int end = buffer->out_len;
- buffer->move_to (mark);
+ if (unlikely (!buffer->move_to (mark))) return;
if (buffer->idx < buffer->len && !before)
- buffer->copy_glyph ();
+ if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
- for (unsigned int i = 0; i < count; i++)
- buffer->output_glyph (glyphs[i]);
+ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
- buffer->move_to (end + count);
+ if (unlikely (!buffer->move_to (end + count))) return;
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
}
@@ -764,10 +763,9 @@ struct InsertionSubtable
unsigned int end = buffer->out_len;
if (buffer->idx < buffer->len && !before)
- buffer->copy_glyph ();
+ if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
- for (unsigned int i = 0; i < count; i++)
- buffer->output_glyph (glyphs[i]);
+ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@@ -786,7 +784,7 @@ struct InsertionSubtable
*
* https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
*/
- buffer->move_to ((flags & DontAdvance) ? end : end + count);
+ if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
}
}
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.cc b/thirdparty/harfbuzz/src/hb-aat-layout.cc
index 74ebaa64ec..0e9f2b4954 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.cc
@@ -227,7 +227,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
*
* <note>Note: does not examine the `GSUB` table.</note>
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -294,7 +294,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
*
* <note>Note: does not examine the `GPOS` table.</note>
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -325,7 +325,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
* Tests whether the specified face includes any tracking information
* in the `trak` table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -350,7 +350,7 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
* hb_aat_layout_get_feature_types:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first feature type to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature types to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature types to return;
* Output = the actual number of feature types returned (may be zero)
* @features: (out caller-allocates) (array length=feature_count): Array of feature types found
*
@@ -374,9 +374,9 @@ hb_aat_layout_get_feature_types (hb_face_t *face,
* @face: #hb_face_t to work upon
* @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
*
- * Fetches the name ID of the specified feature type in the face's `name` table.
+ * Fetches the name identifier of the specified feature type in the face's `name` table.
*
- * Return value: Name ID of the requested feature type
+ * Return value: Name identifier of the requested feature type
*
* Since: 2.2.0
*/
@@ -388,15 +388,15 @@ hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
}
/**
- * hb_aat_layout_feature_type_get_selectors:
+ * hb_aat_layout_feature_type_get_selector_infos:
* @face: #hb_face_t to work upon
* @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
* @start_offset: offset of the first feature type to retrieve
- * @selector_count: (inout) (allow-none): Input = the maximum number of selectors to return;
+ * @selector_count: (inout) (optional): Input = the maximum number of selectors to return;
* Output = the actual number of selectors returned (may be zero)
- * @selectors: (out caller-allocates) (array length=selector_count): A buffer pointer.
- * The selectors available for the feature type queries.
- * @default_index: (out) (allow-none): The index of the feature's default selector, if any
+ * @selectors: (out caller-allocates) (array length=selector_count) (optional):
+ * A buffer pointer. The selectors available for the feature type queries.
+ * @default_index: (out) (optional): The index of the feature's default selector, if any
*
* Fetches a list of the selectors available for the specified feature in the given face.
*
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.h b/thirdparty/harfbuzz/src/hb-aat-layout.h
index dc1bf96573..9af2740088 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.h
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_AAT_H_IN
+#if !defined(HB_AAT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-aat.h> instead."
#endif
@@ -38,47 +38,47 @@ HB_BEGIN_DECLS
/**
* hb_aat_layout_feature_type_t:
* @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE:
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING: [Number Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type6)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE: [Smart Swash](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type8)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE: [Diacritics](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type9)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION: [Vertical Position](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type10)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS: [Fractions](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type11)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE: [Overlapping Characters](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type13)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS: [Typographic Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type14)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS: [Mathematical Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type15)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE: [Ornament Sets](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type16)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES: [Character Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type17)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE: [Design Complexity](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type18)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS: [Style Options](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type19)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE: [Character Shape](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type20)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE: [Number Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type21)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING: [Text Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type22)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION: [Transliteration](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type23)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE: [Annotation](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type24)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE: [Kana Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type25)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE: [Ideographic Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type26)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE: [Unicode Decomposition](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type27)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA: [Ruby Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type28)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE: [CJK Symbol Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type29)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE: [Ideographic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type30)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE: [CJK Vertical Roman Placement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type31)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN: [Italic CJK Roman](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type32)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT: [Case Sensitive Layout](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type33)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA: [Alternate Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type34)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES: [Stylistic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type35)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES: [Contextual Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type36)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE: [Lower Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type37)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE: [Upper Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type38)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE: [Language Tag](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type39)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE: [CJK Roman Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type103)
*
- * The possible feature types defined for AAT shaping.
+ * The possible feature types defined for AAT shaping, from Apple [Font Feature Registry](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html).
*
* Since: 2.2.0
*/
@@ -732,6 +732,14 @@ HB_EXTERN hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type);
+/**
+ * hb_aat_layout_feature_selector_info_t:
+ * @name_id: The selector's name identifier
+ * @enable: The value to turn the selector on
+ * @disable: The value to turn the selector off
+ *
+ * Structure representing a setting for an #hb_aat_layout_feature_type_t.
+ */
typedef struct hb_aat_layout_feature_selector_info_t {
hb_ot_name_id_t name_id;
hb_aat_layout_feature_selector_t enable;
diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index 98de61f3e8..bc170b0546 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -35,6 +35,132 @@
#include "hb-number.hh"
+/*
+ * Flags
+ */
+
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another... So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+ * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+ extern "C++" { \
+ static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
+ static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
+ static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
+ static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
+ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
+ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+ } \
+ static_assert (true, "")
+
+/* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+#define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
+#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
+#define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x))
+#define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
+#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
+
+
+/*
+ * Big-endian integers.
+ */
+
+/* Endian swap, used in Windows related backends */
+static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+template <typename Type, int Bytes = sizeof (Type)>
+struct BEInt;
+template <typename Type>
+struct BEInt<Type, 1>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t (V)} {}
+ constexpr operator Type () const { return v; }
+ private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+
+ struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+ constexpr operator Type () const
+ {
+#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+ defined(__BYTE_ORDER) && \
+ (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+ /* Spoon-feed the compiler a big-endian integer with alignment 1.
+ * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ return ((packed_uint16_t *) this)->v;
+#endif
+#else
+ return (v[0] << 8)
+ + (v[1] );
+#endif
+ }
+ private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+ static_assert (!hb_is_signed (Type), "");
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+
+ constexpr operator Type () const { return (v[0] << 16)
+ + (v[1] << 8)
+ + (v[2] ); }
+ private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
+ uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+ constexpr operator Type () const { return (v[0] << 24)
+ + (v[1] << 16)
+ + (v[2] << 8)
+ + (v[3] ); }
+ private: uint8_t v[4];
+};
+
+/* Floats. */
+
+/* We want our rounding towards +infinity. */
+static inline float
+_hb_roundf (float x) { return floorf (x + .5f); }
+#define roundf(x) _hb_roundf(x)
+
+
/* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits,
* values will be truncated / overlap, and might not decode exactly. */
#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
@@ -48,6 +174,7 @@
#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
+
struct
{
/* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
@@ -215,7 +342,9 @@ struct
template <typename Pred, typename Val> auto
impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
- (hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
+ (
+ hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v))
+ )
template <typename Pred, typename Val> auto
impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
@@ -269,7 +398,9 @@ struct
template <typename Proj, typename Val> auto
impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
- (hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
+ (
+ hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v))
+ )
template <typename Proj, typename Val> auto
impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
@@ -296,6 +427,40 @@ struct
}
HB_FUNCOBJ (hb_get);
+struct
+{
+ private:
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
+ (
+ hb_forward<T2> (v2).cmp (hb_forward<T1> (v1)) == 0
+ )
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
+ (
+ hb_forward<T1> (v1).cmp (hb_forward<T2> (v2)) == 0
+ )
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
+ (
+ hb_forward<T1> (v1) == hb_forward<T2> (v2)
+ )
+
+ public:
+
+ template <typename T1, typename T2> auto
+ operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN
+ (
+ impl (hb_forward<T1> (v1),
+ hb_forward<T2> (v2),
+ hb_prioritize)
+ )
+}
+HB_FUNCOBJ (hb_equal);
+
template <typename T1, typename T2>
struct hb_pair_t
@@ -375,7 +540,7 @@ HB_FUNCOBJ (hb_clamp);
/* Return the number of 1 bits in v. */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_popcount (T v)
{
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
@@ -416,7 +581,7 @@ hb_popcount (T v)
/* Returns the number of bits needed to store number */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
@@ -490,7 +655,7 @@ hb_bit_storage (T v)
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return 8 * sizeof (T);
@@ -988,32 +1153,24 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
struct hb_bitwise_and
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = false;
- static constexpr bool passthru_right = false;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
}
HB_FUNCOBJ (hb_bitwise_and);
struct hb_bitwise_or
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = true;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
}
HB_FUNCOBJ (hb_bitwise_or);
struct hb_bitwise_xor
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = true;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
}
HB_FUNCOBJ (hb_bitwise_xor);
struct hb_bitwise_sub
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = false;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
}
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 568cd02c79..02bd8d81c2 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -142,7 +142,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
bool lfind (const T &x, unsigned *pos = nullptr) const
{
for (unsigned i = 0; i < length; ++i)
- if (!this->arrayZ[i].cmp (x))
+ if (hb_equal (x, this->arrayZ[i]))
{
if (pos)
*pos = i;
diff --git a/thirdparty/harfbuzz/src/hb-atomic.hh b/thirdparty/harfbuzz/src/hb-atomic.hh
index b3fb296b4e..93265f655f 100644
--- a/thirdparty/harfbuzz/src/hb-atomic.hh
+++ b/thirdparty/harfbuzz/src/hb-atomic.hh
@@ -52,7 +52,7 @@
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
-/* C++11-style GCC primitives. */
+/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
#define _hb_memory_barrier() __sync_synchronize ()
@@ -73,7 +73,8 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
-#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
+
+#elif !defined(HB_NO_MT)
/* C++11 atomics. */
@@ -101,117 +102,6 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
-#elif !defined(HB_NO_MT) && defined(_WIN32)
-
-#include <windows.h>
-
-static inline void _hb_memory_barrier ()
-{
-#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
- /* MinGW has a convoluted history of supporting MemoryBarrier. */
- LONG dummy = 0;
- InterlockedExchange (&dummy, 1);
-#else
- MemoryBarrier ();
-#endif
-}
-#define _hb_memory_barrier() _hb_memory_barrier ()
-
-#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
-static_assert ((sizeof (LONG) == sizeof (int)), "");
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-#define _hb_memory_barrier() __sync_synchronize ()
-
-#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
-
-#include <atomic.h>
-#include <mbarrier.h>
-
-#define _hb_memory_r_barrier() __machine_r_barrier ()
-#define _hb_memory_w_barrier() __machine_w_barrier ()
-#define _hb_memory_barrier() __machine_rw_barrier ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
- _hb_memory_w_barrier ();
- int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
- _hb_memory_r_barrier ();
- return result;
-}
-static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
-{
- _hb_memory_w_barrier ();
- bool result = atomic_cas_ptr (P, O, N) == O;
- _hb_memory_r_barrier ();
- return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(__APPLE__)
-
-#include <libkern/OSAtomic.h>
-#ifdef __MAC_OS_X_MIN_REQUIRED
-#include <AvailabilityMacros.h>
-#elif defined(__IPHONE_OS_MIN_REQUIRED)
-#include <Availability.h>
-#endif
-
-#define _hb_memory_barrier() OSMemoryBarrier ()
-
-#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
-
-#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
-#else
-#if __ppc64__ || __x86_64__ || __aarch64__
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
-#else
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
-#endif
-#endif
-
-
-#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
-
-#include <builtins.h>
-
-#define _hb_memory_barrier() __lwsync ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
- _hb_memory_barrier ();
- int result = __fetch_and_add (AI, V);
- _hb_memory_barrier ();
- return result;
-}
-static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
-{
- _hb_memory_barrier ();
- bool result = __compare_and_swaplp (P, &O, N);
- _hb_memory_barrier ();
- return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N))
-static_assert ((sizeof (long) == sizeof (void *)), "");
-
-
#elif defined(HB_NO_MT)
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@@ -259,9 +149,11 @@ inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory
#endif
-#define HB_ATOMIC_INT_INIT(V) {V}
struct hb_atomic_int_t
{
+ hb_atomic_int_t () = default;
+ constexpr hb_atomic_int_t (int v) : v (v) {}
+
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
@@ -269,16 +161,17 @@ struct hb_atomic_int_t
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
- int v;
+ int v = 0;
};
-
-#define HB_ATOMIC_PTR_INIT(V) {V}
template <typename P>
struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
+ hb_atomic_ptr_t () = default;
+ constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
@@ -288,7 +181,7 @@ struct hb_atomic_ptr_t
T * operator -> () const { return get (); }
template <typename C> operator C * () const { return get (); }
- T *v;
+ T *v = nullptr;
};
diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc
index e340bc346d..71b1b1fc4f 100644
--- a/thirdparty/harfbuzz/src/hb-blob.cc
+++ b/thirdparty/harfbuzz/src/hb-blob.cc
@@ -35,9 +35,6 @@
#include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */
-#include <stdio.h>
-#include <stdlib.h>
-
/**
* SECTION: hb-blob
@@ -58,7 +55,7 @@
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
- * @destroy: (optional): Callback to call when @data is not needed anymore.
+ * @destroy: (nullable): Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
@@ -116,7 +113,7 @@ _hb_blob_destroy (void *data)
* @length: Length of sub-blob.
*
* Returns a blob that represents a range of bytes in @parent. The new
- * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * blob is always created with #HB_MEMORY_MODE_READONLY, meaning that it
* will never modify data in the parent blob. The parent data is not
* expected to be modified, and will result in undefined behavior if it
* is.
@@ -237,7 +234,7 @@ hb_blob_destroy (hb_blob_t *blob)
* @blob: An #hb_blob_t
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified blob.
@@ -299,7 +296,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
*
* Tests whether a blob is immutable.
*
- * Return value: %true if @blob is immutable, false otherwise
+ * Return value: %true if @blob is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -365,16 +362,14 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
{
- if (!blob->try_make_writable ()) {
- if (length)
- *length = 0;
-
+ if (hb_object_is_immutable (blob) ||
+ !blob->try_make_writable ())
+ {
+ if (length) *length = 0;
return nullptr;
}
- if (length)
- *length = blob->length;
-
+ if (length) *length = blob->length;
return const_cast<char *> (blob->data);
}
@@ -440,8 +435,8 @@ hb_blob_t::try_make_writable_inplace ()
bool
hb_blob_t::try_make_writable ()
{
- if (hb_object_is_immutable (this))
- return false;
+ if (unlikely (!length))
+ mode = HB_MEMORY_MODE_WRITABLE;
if (this->mode == HB_MEMORY_MODE_WRITABLE)
return true;
diff --git a/thirdparty/harfbuzz/src/hb-blob.h b/thirdparty/harfbuzz/src/hb-blob.h
index 00e41f3ce3..86f12788d2 100644
--- a/thirdparty/harfbuzz/src/hb-blob.h
+++ b/thirdparty/harfbuzz/src/hb-blob.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -38,10 +38,12 @@ HB_BEGIN_DECLS
/**
* hb_memory_mode_t:
- * @HB_MEMORY_MODE_DUPLICATE
- * @HB_MEMORY_MODE_READONLY
- * @HB_MEMORY_MODE_WRITABLE
- * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
+ * @HB_MEMORY_MODE_DUPLICATE: HarfBuzz immediately makes a copy of the data.
+ * @HB_MEMORY_MODE_READONLY: HarfBuzz client will never modify the data,
+ * and HarfBuzz will never modify the data.
+ * @HB_MEMORY_MODE_WRITABLE: HarfBuzz client made a copy of the data solely
+ * for HarfBuzz, so HarfBuzz may modify the data.
+ * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE: See above
*
* Data type holding the memory modes available to
* client programs.
diff --git a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
index f65bad45bb..6539b89640 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
@@ -400,8 +400,8 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
- * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
@@ -514,8 +514,10 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
+ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
+ * to serialize.
*
* Serializes @buffer into a textual representation of its content,
* when the buffer contains Unicode codepoints (i.e., before shaping). This is
@@ -635,8 +637,8 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
- * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
@@ -724,15 +726,17 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
/**
* hb_buffer_deserialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
- * @buf: (array length=buf_len):
- * @buf_len:
- * @end_ptr: (out):
- * @font:
- * @format:
- *
+ * @buf: (array length=buf_len): string to deserialize
+ * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @end_ptr: (out) (optional): output pointer to the character after last
+ * consumed one.
+ * @font: (nullable): font for getting glyph IDs
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
*
+ * Deserializes glyphs @buffer from textual representation in the format
+ * produced by hb_buffer_serialize_glyphs().
*
- * Return value:
+ * Return value: %true if @buf is not fully consumed, %false otherwise.
*
* Since: 0.9.7
**/
@@ -795,14 +799,16 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
/**
* hb_buffer_deserialize_unicode:
* @buffer: an #hb_buffer_t buffer.
- * @buf: (array length=buf_len):
- * @buf_len:
- * @end_ptr: (out):
- * @format:
- *
+ * @buf: (array length=buf_len): string to deserialize
+ * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @end_ptr: (out) (optional): output pointer to the character after last
+ * consumed one.
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
*
+ * Deserializes Unicode @buffer from textual representation in the format
+ * produced by hb_buffer_serialize_unicode().
*
- * Return value:
+ * Return value: %true if @buf is not fully consumed, %false otherwise.
*
* Since: 2.7.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc
index 10063db050..8cad6ab8e6 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer.cc
@@ -218,9 +218,6 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
void
hb_buffer_t::reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
@@ -233,9 +230,6 @@ hb_buffer_t::reset ()
void
hb_buffer_t::clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
@@ -290,9 +284,6 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
void
hb_buffer_t::remove_output ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = false;
have_positions = false;
@@ -303,9 +294,6 @@ hb_buffer_t::remove_output ()
void
hb_buffer_t::clear_output ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = true;
have_positions = false;
@@ -316,9 +304,6 @@ hb_buffer_t::clear_output ()
void
hb_buffer_t::clear_positions ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = false;
have_positions = true;
@@ -333,15 +318,19 @@ hb_buffer_t::swap_buffers ()
{
if (unlikely (!successful)) return;
+ assert (idx <= len);
+ if (unlikely (!next_glyphs (len - idx))) return;
+
assert (have_output);
have_output = false;
if (out_info != info)
{
- hb_glyph_info_t *tmp_string;
- tmp_string = info;
+ hb_glyph_info_t *tmp;
+ tmp = info;
info = out_info;
- out_info = tmp_string;
+ out_info = tmp;
+
pos = (hb_glyph_position_t *) out_info;
}
@@ -353,31 +342,6 @@ hb_buffer_t::swap_buffers ()
idx = 0;
}
-
-void
-hb_buffer_t::replace_glyphs (unsigned int num_in,
- unsigned int num_out,
- const uint32_t *glyph_data)
-{
- if (unlikely (!make_room_for (num_in, num_out))) return;
-
- assert (idx + num_in <= len);
-
- merge_clusters (idx, idx + num_in);
-
- hb_glyph_info_t orig_info = info[idx];
- hb_glyph_info_t *pinfo = &out_info[out_len];
- for (unsigned int i = 0; i < num_out; i++)
- {
- *pinfo = orig_info;
- pinfo->codepoint = glyph_data[i];
- pinfo++;
- }
-
- idx += num_in;
- out_len += num_out;
-}
-
bool
hb_buffer_t::move_to (unsigned int i)
{
@@ -768,7 +732,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
* @buffer: An #hb_buffer_t
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified buffer.
@@ -795,7 +759,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
* Fetches the user data associated with the specified key,
* attached to the specified buffer.
*
- * Return value: (transfer-none): A pointer to the user data
+ * Return value: (transfer none): A pointer to the user data
*
* Since: 0.9.2
**/
@@ -1137,7 +1101,7 @@ hb_buffer_get_cluster_level (hb_buffer_t *buffer)
* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
* when adding text to @buffer.
*
- * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
*
* Since: 0.9.31
**/
@@ -1222,6 +1186,9 @@ hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
void
hb_buffer_reset (hb_buffer_t *buffer)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
buffer->reset ();
}
@@ -1237,6 +1204,9 @@ hb_buffer_reset (hb_buffer_t *buffer)
void
hb_buffer_clear_contents (hb_buffer_t *buffer)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
buffer->clear ();
}
@@ -1321,7 +1291,7 @@ hb_buffer_set_length (hb_buffer_t *buffer,
if (unlikely (hb_object_is_immutable (buffer)))
return length == 0;
- if (!buffer->ensure (length))
+ if (unlikely (!buffer->ensure (length)))
return false;
/* Wipe the new space */
@@ -1501,20 +1471,20 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
*
* Sets unset buffer segment properties based on buffer Unicode
* contents. If buffer is not empty, it must have content type
- * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ * #HB_BUFFER_CONTENT_TYPE_UNICODE.
*
- * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it
* will be set to the Unicode script of the first character in
- * the buffer that has a script other than %HB_SCRIPT_COMMON,
- * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ * the buffer that has a script other than #HB_SCRIPT_COMMON,
+ * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.
*
- * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),
* it will be set to the natural horizontal direction of the
* buffer script as returned by hb_script_get_horizontal_direction().
- * If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID,
- * then %HB_DIRECTION_LTR is used.
+ * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,
+ * then #HB_DIRECTION_LTR is used.
*
- * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),
* it will be set to the process's default language as returned by
* hb_language_get_default(). This may change in the future by
* taking buffer script into consideration when choosing a language.
@@ -1551,7 +1521,10 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
if (item_length == -1)
item_length = text_length - item_offset;
- buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+ if (unlikely (item_length < 0 ||
+ item_length > INT_MAX / 8 ||
+ !buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
+ return;
/* If buffer is empty and pre-context provided, install it.
* This check is written this way, to make sure people can
@@ -1768,11 +1741,6 @@ hb_buffer_append (hb_buffer_t *buffer,
if (start == end)
return;
- if (!buffer->len)
- buffer->content_type = source->content_type;
- if (!buffer->have_positions && source->have_positions)
- buffer->clear_positions ();
-
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
{
buffer->successful = false;
@@ -1784,6 +1752,11 @@ hb_buffer_append (hb_buffer_t *buffer,
if (unlikely (!buffer->successful))
return;
+ if (!orig_len)
+ buffer->content_type = source->content_type;
+ if (!buffer->have_positions && source->have_positions)
+ buffer->clear_positions ();
+
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
@@ -1902,8 +1875,8 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
* @position_fuzz: allowed absolute difference in position values.
*
- * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
- * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
+ * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+ * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
* callers if just comparing two buffers is needed.
*
* Since: 1.5.0
@@ -1994,11 +1967,11 @@ hb_buffer_diff (hb_buffer_t *buffer,
/**
* hb_buffer_set_message_func:
* @buffer: An #hb_buffer_t
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
+ * @func: (closure user_data) (destroy destroy) (scope notified): Callback function
+ * @user_data: (nullable): Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
+ * Sets the implementation function for #hb_buffer_message_func_t.
*
* Since: 1.1.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h
index b13757e68f..865ccb2273 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.h
+++ b/thirdparty/harfbuzz/src/hb-buffer.h
@@ -27,7 +27,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -90,6 +90,8 @@ typedef struct hb_glyph_info_t {
* breaking point only.
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
+ * Flags for #hb_glyph_info_t.
+ *
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
@@ -150,6 +152,11 @@ typedef struct hb_segment_properties_t {
void *reserved2;
} hb_segment_properties_t;
+/**
+ * HB_SEGMENT_PROPERTIES_DEFAULT:
+ *
+ * The default #hb_segment_properties_t of of freshly created #hb_buffer_t.
+ */
#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
HB_SCRIPT_INVALID, \
HB_LANGUAGE_INVALID, \
@@ -203,6 +210,8 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
* @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
* @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ *
+ * The type of #hb_buffer_t contents.
*/
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
@@ -288,6 +297,8 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
*
+ * Flags for #hb_buffer_t.
+ *
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
@@ -579,6 +590,35 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
* Compare buffers
*/
+/**
+ * hb_buffer_diff_flags_t:
+ * @HB_BUFFER_DIFF_FLAG_EQUAL: equal buffers.
+ * @HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH: buffers with different
+ * #hb_buffer_content_type_t.
+ * @HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH: buffers with differing length.
+ * @HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT: `.notdef` glyph is present in the
+ * reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT: dotted circle glyph is present
+ * in the reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH: difference in #hb_glyph_info_t.codepoint
+ * @HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH: difference in #hb_glyph_info_t.cluster
+ * @HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH: difference in #hb_glyph_flags_t.
+ * @HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH: difference in #hb_glyph_position_t.
+ *
+ * Flags from comparing two #hb_buffer_t's.
+ *
+ * Buffer with different #hb_buffer_content_type_t cannot be meaningfully
+ * compared in any further detail.
+ *
+ * For buffers with differing length, the per-glyph comparison is not
+ * attempted, though we do still scan reference buffer for dotted circle and
+ * `.notdef` glyphs.
+ *
+ * If the buffers have the same length, we compare them glyph-by-glyph and
+ * report which aspect(s) of the glyph info/position are different.
+ *
+ * Since: 1.5.0
+ */
typedef enum { /*< flags >*/
HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000,
@@ -618,6 +658,23 @@ hb_buffer_diff (hb_buffer_t *buffer,
* Debugging.
*/
+/**
+ * hb_buffer_message_func_t:
+ * @buffer: An #hb_buffer_t to work upon
+ * @font: The #hb_font_t the @buffer is shaped with
+ * @message: %NULL-terminated message passed to the function
+ * @user_data: User data pointer passed by the caller
+ *
+ * A callback method for #hb_buffer_t. The method gets called with the
+ * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
+ * message describing what step of the shaping process will be performed.
+ * Returning %false from this method will skip this shaping step and move to
+ * the next one.
+ *
+ * Return value: %true to perform the shaping step, %false to skip it.
+ *
+ * Since: 1.1.3
+ */
typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer,
hb_font_t *font,
const char *message,
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index 9cad5206e2..8b432b5f96 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -139,7 +139,7 @@ struct hb_buffer_t
/* Methods */
- bool in_error () const { return !successful; }
+ HB_NODISCARD bool in_error () const { return !successful; }
void allocate_var (unsigned int start, unsigned int count)
{
@@ -186,7 +186,7 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
- bool has_separate_output () const { return info != out_info; }
+ HB_NODISCARD bool has_separate_output () const { return info != out_info; }
HB_INTERNAL void reset ();
@@ -210,86 +210,89 @@ struct hb_buffer_t
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
- HB_INTERNAL void replace_glyphs (unsigned int num_in,
- unsigned int num_out,
- const hb_codepoint_t *glyph_data);
-
- void replace_glyph (hb_codepoint_t glyph_index)
+ template <typename T>
+ HB_NODISCARD bool replace_glyphs (unsigned int num_in,
+ unsigned int num_out,
+ const T *glyph_data)
{
- if (unlikely (out_info != info || out_len != idx)) {
- if (unlikely (!make_room_for (1, 1))) return;
- out_info[out_len] = info[idx];
- }
- out_info[out_len].codepoint = glyph_index;
+ if (unlikely (!make_room_for (num_in, num_out))) return false;
- idx++;
- out_len++;
- }
- /* Makes a copy of the glyph at idx to output and replace glyph_index */
- hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
- {
- if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t);
+ assert (idx + num_in <= len);
- if (unlikely (idx == len && !out_len))
- return Crap (hb_glyph_info_t);
+ merge_clusters (idx, idx + num_in);
- out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
- out_info[out_len].codepoint = glyph_index;
+ hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
- out_len++;
+ hb_glyph_info_t *pinfo = &out_info[out_len];
+ for (unsigned int i = 0; i < num_out; i++)
+ {
+ *pinfo = orig_info;
+ pinfo->codepoint = glyph_data[i];
+ pinfo++;
+ }
- return out_info[out_len - 1];
+ idx += num_in;
+ out_len += num_out;
+ return true;
}
- void output_info (const hb_glyph_info_t &glyph_info)
+
+ HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
+ { return replace_glyphs (1, 1, &glyph_index); }
+
+ /* Makes a copy of the glyph at idx to output and replace glyph_index */
+ HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
+ { return replace_glyphs (0, 1, &glyph_index); }
+
+ HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
{
- if (unlikely (!make_room_for (0, 1))) return;
+ if (unlikely (!make_room_for (0, 1))) return false;
out_info[out_len] = glyph_info;
out_len++;
+ return true;
}
/* Copies glyph at idx to output but doesn't advance idx */
- void copy_glyph ()
+ HB_NODISCARD bool copy_glyph ()
{
- if (unlikely (!make_room_for (0, 1))) return;
-
- out_info[out_len] = info[idx];
-
- out_len++;
+ /* Extra copy because cur()'s return can be freed within
+ * output_info() call if buffer reallocates. */
+ return output_info (hb_glyph_info_t (cur()));
}
+
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
- void
- next_glyph ()
+ HB_NODISCARD bool next_glyph ()
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
- if (unlikely (!make_room_for (1, 1))) return;
+ if (unlikely (!make_room_for (1, 1))) return false;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
+ return true;
}
/* Copies n glyphs at idx to output and advance idx.
* If there's no output, just advance idx. */
- void
- next_glyphs (unsigned int n)
+ HB_NODISCARD bool next_glyphs (unsigned int n)
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
- if (unlikely (!make_room_for (n, n))) return;
+ if (unlikely (!make_room_for (n, n))) return false;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
}
idx += n;
+ return true;
}
/* Advance idx without copying to output. */
void skip_glyph () { idx++; }
@@ -329,14 +332,14 @@ struct hb_buffer_t
/* Internal methods */
- HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+ HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
- HB_INTERNAL bool enlarge (unsigned int size);
+ HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
- bool ensure (unsigned int size)
+ HB_NODISCARD bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
- bool ensure_inplace (unsigned int size)
+ HB_NODISCARD bool ensure_inplace (unsigned int size)
{ return likely (!size || size < allocated); }
void assert_glyphs ()
@@ -349,7 +352,7 @@ struct hb_buffer_t
assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
(!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
}
- bool ensure_glyphs ()
+ HB_NODISCARD bool ensure_glyphs ()
{
if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
{
@@ -360,7 +363,7 @@ struct hb_buffer_t
}
return true;
}
- bool ensure_unicode ()
+ HB_NODISCARD bool ensure_unicode ()
{
if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
{
@@ -372,8 +375,8 @@ struct hb_buffer_t
return true;
}
- HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
- HB_INTERNAL bool shift_forward (unsigned int count);
+ HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+ HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc
index ddbcaa064c..7bb878b217 100644
--- a/thirdparty/harfbuzz/src/hb-common.cc
+++ b/thirdparty/harfbuzz/src/hb-common.cc
@@ -675,8 +675,8 @@ hb_version_string ()
* Tests the library version against a minimum value,
* as three integer components.
*
- * Return value: True if the library is equal to or greater than
- * the test value, false otherwise
+ * Return value: %true if the library is equal to or greater than
+ * the test value, %false otherwise
*
* Since: 0.9.30
**/
@@ -1003,6 +1003,21 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
/**
* hb_variation_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ * @variation: (out): the #hb_variation_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_variation_t.
+ *
+ * The format for specifying variation settings follows. All valid CSS
+ * font-variation-settings values other than 'normal' and 'inherited' are also
+ * accepted, though, not documented below.
+ *
+ * The format is a tag, optionally followed by an equals sign, followed by a
+ * number. For example `wght=500`, or `slnt=-7.5`.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise
*
* Since: 1.4.2
*/
@@ -1029,6 +1044,13 @@ hb_variation_from_string (const char *str, int len,
/**
* hb_variation_to_string:
+ * @variation: an #hb_variation_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * understood by hb_variation_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 1.4.2
*/
@@ -1055,9 +1077,11 @@ hb_variation_to_string (hb_variation_t *variation,
/**
* hb_color_get_alpha:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
*
- * Return value: Alpha channel value of the given color
+ * Fetches the alpha channel of the given @color.
+ *
+ * Return value: Alpha channel value
*
* Since: 2.1.0
*/
@@ -1069,9 +1093,11 @@ uint8_t
/**
* hb_color_get_red:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the red channel of the given @color.
*
- * Return value: Red channel value of the given color
+ * Return value: Red channel value
*
* Since: 2.1.0
*/
@@ -1083,9 +1109,11 @@ uint8_t
/**
* hb_color_get_green:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
*
- * Return value: Green channel value of the given color
+ * Fetches the green channel of the given @color.
+ *
+ * Return value: Green channel value
*
* Since: 2.1.0
*/
@@ -1097,9 +1125,11 @@ uint8_t
/**
* hb_color_get_blue:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the blue channel of the given @color.
*
- * Return value: Blue channel value of the given color
+ * Return value: Blue channel value
*
* Since: 2.1.0
*/
diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h
index efe185cdfd..532fd428cb 100644
--- a/thirdparty/harfbuzz/src/hb-common.h
+++ b/thirdparty/harfbuzz/src/hb-common.h
@@ -26,7 +26,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -135,7 +135,7 @@ typedef union _hb_var_int_t {
/**
* hb_tag_t:
- *
+ *
* Data type for tag identifiers. Tags are four
* byte integers, each byte representing a character.
*
@@ -148,22 +148,48 @@ typedef uint32_t hb_tag_t;
/**
* HB_TAG:
+ * @c1: 1st character of the tag
+ * @c2: 2nd character of the tag
+ * @c3: 3rd character of the tag
+ * @c4: 4th character of the tag
*
- * Constructs an #hb_tag_t from four characters.
+ * Constructs an #hb_tag_t from four character literals.
*
**/
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
/**
* HB_UNTAG:
+ * @tag: an #hb_tag_t
+ *
+ * Extracts four character literals from an #hb_tag_t.
*
- * Extracts the characters from an #hb_tag_t.
+ * Since: 0.6.0
*
**/
#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
+/**
+ * HB_TAG_NONE:
+ *
+ * Unset #hb_tag_t.
+ */
#define HB_TAG_NONE HB_TAG(0,0,0,0)
+/**
+ * HB_TAG_MAX:
+ *
+ * Maximum possible unsigned #hb_tag_t.
+ *
+ * Since: 0.9.26
+ */
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+/**
+ * HB_TAG_MAX_SIGNED:
+ *
+ * Maximum possible signed #hb_tag_t.
+ *
+ * Since: 0.9.33
+ */
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
@@ -263,6 +289,13 @@ hb_direction_to_string (hb_direction_t direction);
/* hb_language_t */
+/**
+ * hb_language_t:
+ *
+ * Data type for languages. Each #hb_language_t corresponds to a BCP 47
+ * language tag.
+ *
+ */
typedef const struct hb_language_impl_t *hb_language_t;
HB_EXTERN hb_language_t
@@ -271,6 +304,13 @@ hb_language_from_string (const char *str, int len);
HB_EXTERN const char *
hb_language_to_string (hb_language_t language);
+/**
+ * HB_LANGUAGE_INVALID:
+ *
+ * An unset #hb_language_t.
+ *
+ * Since: 0.6.0
+ */
#define HB_LANGUAGE_INVALID ((hb_language_t) 0)
HB_EXTERN hb_language_t
@@ -279,160 +319,164 @@ hb_language_get_default (void);
/**
* hb_script_t:
- * @HB_SCRIPT_COMMON: HB_TAG ('Z','y','y','y')
- * @HB_SCRIPT_INHERITED: HB_TAG ('Z','i','n','h')
- * @HB_SCRIPT_UNKNOWN: HB_TAG ('Z','z','z','z')
- * @HB_SCRIPT_ARABIC
- * @HB_SCRIPT_ARMENIAN
- * @HB_SCRIPT_BENGALI
- * @HB_SCRIPT_CYRILLIC
- * @HB_SCRIPT_DEVANAGARI
- * @HB_SCRIPT_GEORGIAN
- * @HB_SCRIPT_GREEK
- * @HB_SCRIPT_GUJARATI
- * @HB_SCRIPT_GURMUKHI
- * @HB_SCRIPT_HANGUL
- * @HB_SCRIPT_HAN
- * @HB_SCRIPT_HEBREW
- * @HB_SCRIPT_HIRAGANA
- * @HB_SCRIPT_KANNADA
- * @HB_SCRIPT_KATAKANA
- * @HB_SCRIPT_LAO
- * @HB_SCRIPT_LATIN
- * @HB_SCRIPT_MALAYALAM
- * @HB_SCRIPT_ORIYA
- * @HB_SCRIPT_TAMIL
- * @HB_SCRIPT_TELUGU
- * @HB_SCRIPT_THAI
- * @HB_SCRIPT_TIBETAN
- * @HB_SCRIPT_BOPOMOFO
- * @HB_SCRIPT_BRAILLE
- * @HB_SCRIPT_CANADIAN_SYLLABICS
- * @HB_SCRIPT_CHEROKEE
- * @HB_SCRIPT_ETHIOPIC
- * @HB_SCRIPT_KHMER
- * @HB_SCRIPT_MONGOLIAN
- * @HB_SCRIPT_MYANMAR
- * @HB_SCRIPT_OGHAM
- * @HB_SCRIPT_RUNIC
- * @HB_SCRIPT_SINHALA
- * @HB_SCRIPT_SYRIAC
- * @HB_SCRIPT_THAANA
- * @HB_SCRIPT_YI
- * @HB_SCRIPT_DESERET
- * @HB_SCRIPT_GOTHIC
- * @HB_SCRIPT_OLD_ITALIC
- * @HB_SCRIPT_BUHID
- * @HB_SCRIPT_HANUNOO
- * @HB_SCRIPT_TAGALOG
- * @HB_SCRIPT_TAGBANWA
- * @HB_SCRIPT_CYPRIOT
- * @HB_SCRIPT_LIMBU
- * @HB_SCRIPT_LINEAR_B
- * @HB_SCRIPT_OSMANYA
- * @HB_SCRIPT_SHAVIAN
- * @HB_SCRIPT_TAI_LE
- * @HB_SCRIPT_UGARITIC
- * @HB_SCRIPT_BUGINESE
- * @HB_SCRIPT_COPTIC
- * @HB_SCRIPT_GLAGOLITIC
- * @HB_SCRIPT_KHAROSHTHI
- * @HB_SCRIPT_NEW_TAI_LUE
- * @HB_SCRIPT_OLD_PERSIAN
- * @HB_SCRIPT_SYLOTI_NAGRI
- * @HB_SCRIPT_TIFINAGH
- * @HB_SCRIPT_BALINESE
- * @HB_SCRIPT_CUNEIFORM
- * @HB_SCRIPT_NKO
- * @HB_SCRIPT_PHAGS_PA
- * @HB_SCRIPT_PHOENICIAN
- * @HB_SCRIPT_CARIAN
- * @HB_SCRIPT_CHAM
- * @HB_SCRIPT_KAYAH_LI
- * @HB_SCRIPT_LEPCHA
- * @HB_SCRIPT_LYCIAN
- * @HB_SCRIPT_LYDIAN
- * @HB_SCRIPT_OL_CHIKI
- * @HB_SCRIPT_REJANG
- * @HB_SCRIPT_SAURASHTRA
- * @HB_SCRIPT_SUNDANESE
- * @HB_SCRIPT_VAI
- * @HB_SCRIPT_AVESTAN
- * @HB_SCRIPT_BAMUM
- * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS
- * @HB_SCRIPT_IMPERIAL_ARAMAIC
- * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI
- * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN
- * @HB_SCRIPT_JAVANESE
- * @HB_SCRIPT_KAITHI
- * @HB_SCRIPT_LISU
- * @HB_SCRIPT_MEETEI_MAYEK
- * @HB_SCRIPT_OLD_SOUTH_ARABIAN
- * @HB_SCRIPT_OLD_TURKIC
- * @HB_SCRIPT_SAMARITAN
- * @HB_SCRIPT_TAI_THAM
- * @HB_SCRIPT_TAI_VIET
- * @HB_SCRIPT_BATAK
- * @HB_SCRIPT_BRAHMI
- * @HB_SCRIPT_MANDAIC
- * @HB_SCRIPT_CHAKMA
- * @HB_SCRIPT_MEROITIC_CURSIVE
- * @HB_SCRIPT_MEROITIC_HIEROGLYPHS
- * @HB_SCRIPT_MIAO
- * @HB_SCRIPT_SHARADA
- * @HB_SCRIPT_SORA_SOMPENG
- * @HB_SCRIPT_TAKRI
- * @HB_SCRIPT_BASSA_VAH
- * @HB_SCRIPT_CAUCASIAN_ALBANIAN
- * @HB_SCRIPT_DUPLOYAN
- * @HB_SCRIPT_ELBASAN
- * @HB_SCRIPT_GRANTHA
- * @HB_SCRIPT_KHOJKI
- * @HB_SCRIPT_KHUDAWADI
- * @HB_SCRIPT_LINEAR_A
- * @HB_SCRIPT_MAHAJANI
- * @HB_SCRIPT_MANICHAEAN
- * @HB_SCRIPT_MENDE_KIKAKUI
- * @HB_SCRIPT_MODI
- * @HB_SCRIPT_MRO
- * @HB_SCRIPT_NABATAEAN
- * @HB_SCRIPT_OLD_NORTH_ARABIAN
- * @HB_SCRIPT_OLD_PERMIC
- * @HB_SCRIPT_PAHAWH_HMONG
- * @HB_SCRIPT_PALMYRENE
- * @HB_SCRIPT_PAU_CIN_HAU
- * @HB_SCRIPT_PSALTER_PAHLAVI
- * @HB_SCRIPT_SIDDHAM
- * @HB_SCRIPT_TIRHUTA
- * @HB_SCRIPT_WARANG_CITI
- * @HB_SCRIPT_AHOM
- * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS
- * @HB_SCRIPT_HATRAN
- * @HB_SCRIPT_MULTANI
- * @HB_SCRIPT_OLD_HUNGARIAN
- * @HB_SCRIPT_SIGNWRITING
- * @HB_SCRIPT_ADLAM
- * @HB_SCRIPT_BHAIKSUKI
- * @HB_SCRIPT_MARCHEN
- * @HB_SCRIPT_OSAGE
- * @HB_SCRIPT_TANGUT
- * @HB_SCRIPT_NEWA
- * @HB_SCRIPT_MASARAM_GONDI
- * @HB_SCRIPT_NUSHU
- * @HB_SCRIPT_SOYOMBO
- * @HB_SCRIPT_ZANABAZAR_SQUARE
- * @HB_SCRIPT_DOGRA
- * @HB_SCRIPT_GUNJALA_GONDI
- * @HB_SCRIPT_HANIFI_ROHINGYA
- * @HB_SCRIPT_MAKASAR
- * @HB_SCRIPT_MEDEFAIDRIN
- * @HB_SCRIPT_OLD_SOGDIAN
- * @HB_SCRIPT_SOGDIAN
- * @HB_SCRIPT_ELYMAIC
- * @HB_SCRIPT_NANDINAGARI
- * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG
- * @HB_SCRIPT_WANCHO
- * @HB_SCRIPT_INVALID: #HB_TAG_NONE
+ * @HB_SCRIPT_COMMON: `Zyyy`
+ * @HB_SCRIPT_INHERITED: `Zinh`
+ * @HB_SCRIPT_UNKNOWN: `Zzzz`
+ * @HB_SCRIPT_ARABIC: `Arab`
+ * @HB_SCRIPT_ARMENIAN: `Armn`
+ * @HB_SCRIPT_BENGALI: `Beng`
+ * @HB_SCRIPT_CYRILLIC: `Cyrl`
+ * @HB_SCRIPT_DEVANAGARI: `Deva`
+ * @HB_SCRIPT_GEORGIAN: `Geor`
+ * @HB_SCRIPT_GREEK: `Grek`
+ * @HB_SCRIPT_GUJARATI: `Gujr`
+ * @HB_SCRIPT_GURMUKHI: `Guru`
+ * @HB_SCRIPT_HANGUL: `Hang`
+ * @HB_SCRIPT_HAN: `Hani`
+ * @HB_SCRIPT_HEBREW: `Hebr`
+ * @HB_SCRIPT_HIRAGANA: `Hira`
+ * @HB_SCRIPT_KANNADA: `Knda`
+ * @HB_SCRIPT_KATAKANA: `Kana`
+ * @HB_SCRIPT_LAO: `Laoo`
+ * @HB_SCRIPT_LATIN: `Latn`
+ * @HB_SCRIPT_MALAYALAM: `Mlym`
+ * @HB_SCRIPT_ORIYA: `Orya`
+ * @HB_SCRIPT_TAMIL: `Taml`
+ * @HB_SCRIPT_TELUGU: `Telu`
+ * @HB_SCRIPT_THAI: `Thai`
+ * @HB_SCRIPT_TIBETAN: `Tibt`
+ * @HB_SCRIPT_BOPOMOFO: `Bopo`
+ * @HB_SCRIPT_BRAILLE: `Brai`
+ * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
+ * @HB_SCRIPT_CHEROKEE: `Cher`
+ * @HB_SCRIPT_ETHIOPIC: `Ethi`
+ * @HB_SCRIPT_KHMER: `Khmr`
+ * @HB_SCRIPT_MONGOLIAN: `Mong`
+ * @HB_SCRIPT_MYANMAR: `Mymr`
+ * @HB_SCRIPT_OGHAM: `Ogam`
+ * @HB_SCRIPT_RUNIC: `Runr`
+ * @HB_SCRIPT_SINHALA: `Sinh`
+ * @HB_SCRIPT_SYRIAC: `Syrc`
+ * @HB_SCRIPT_THAANA: `Thaa`
+ * @HB_SCRIPT_YI: `Yiii`
+ * @HB_SCRIPT_DESERET: `Dsrt`
+ * @HB_SCRIPT_GOTHIC: `Goth`
+ * @HB_SCRIPT_OLD_ITALIC: `Ital`
+ * @HB_SCRIPT_BUHID: `Buhd`
+ * @HB_SCRIPT_HANUNOO: `Hano`
+ * @HB_SCRIPT_TAGALOG: `Tglg`
+ * @HB_SCRIPT_TAGBANWA: `Tagb`
+ * @HB_SCRIPT_CYPRIOT: `Cprt`
+ * @HB_SCRIPT_LIMBU: `Limb`
+ * @HB_SCRIPT_LINEAR_B: `Linb`
+ * @HB_SCRIPT_OSMANYA: `Osma`
+ * @HB_SCRIPT_SHAVIAN: `Shaw`
+ * @HB_SCRIPT_TAI_LE: `Tale`
+ * @HB_SCRIPT_UGARITIC: `Ugar`
+ * @HB_SCRIPT_BUGINESE: `Bugi`
+ * @HB_SCRIPT_COPTIC: `Copt`
+ * @HB_SCRIPT_GLAGOLITIC: `Glag`
+ * @HB_SCRIPT_KHAROSHTHI: `Khar`
+ * @HB_SCRIPT_NEW_TAI_LUE: `Talu`
+ * @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
+ * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
+ * @HB_SCRIPT_TIFINAGH: `Tfng`
+ * @HB_SCRIPT_BALINESE: `Bali`
+ * @HB_SCRIPT_CUNEIFORM: `Xsux`
+ * @HB_SCRIPT_NKO: `Nkoo`
+ * @HB_SCRIPT_PHAGS_PA: `Phag`
+ * @HB_SCRIPT_PHOENICIAN: `Phnx`
+ * @HB_SCRIPT_CARIAN: `Cari`
+ * @HB_SCRIPT_CHAM: `Cham`
+ * @HB_SCRIPT_KAYAH_LI: `Kali`
+ * @HB_SCRIPT_LEPCHA: `Lepc`
+ * @HB_SCRIPT_LYCIAN: `Lyci`
+ * @HB_SCRIPT_LYDIAN: `Lydi`
+ * @HB_SCRIPT_OL_CHIKI: `Olck`
+ * @HB_SCRIPT_REJANG: `Rjng`
+ * @HB_SCRIPT_SAURASHTRA: `Saur`
+ * @HB_SCRIPT_SUNDANESE: `Sund`
+ * @HB_SCRIPT_VAI: `Vaii`
+ * @HB_SCRIPT_AVESTAN: `Avst`
+ * @HB_SCRIPT_BAMUM: `Bamu`
+ * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
+ * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
+ * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
+ * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
+ * @HB_SCRIPT_JAVANESE: `Java`
+ * @HB_SCRIPT_KAITHI: `Kthi`
+ * @HB_SCRIPT_LISU: `Lisu`
+ * @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
+ * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
+ * @HB_SCRIPT_OLD_TURKIC: `Orkh`
+ * @HB_SCRIPT_SAMARITAN: `Samr`
+ * @HB_SCRIPT_TAI_THAM: `Lana`
+ * @HB_SCRIPT_TAI_VIET: `Tavt`
+ * @HB_SCRIPT_BATAK: `Batk`
+ * @HB_SCRIPT_BRAHMI: `Brah`
+ * @HB_SCRIPT_MANDAIC: `Mand`
+ * @HB_SCRIPT_CHAKMA: `Cakm`
+ * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
+ * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
+ * @HB_SCRIPT_MIAO: `Plrd`
+ * @HB_SCRIPT_SHARADA: `Shrd`
+ * @HB_SCRIPT_SORA_SOMPENG: `Sora`
+ * @HB_SCRIPT_TAKRI: `Takr`
+ * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
+ * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
+ * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
+ * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
+ * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
+ * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
+ * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
+ * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
+ * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
+ * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
+ * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
+ * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
+ * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
+ * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
+ * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
+ * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
+ * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
+ * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
+ * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
+ * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
+ * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
+ * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
+ * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
+ * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
+ * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
+ * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
+ * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
+ * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
+ * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
+ * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
+ * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
+ * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
+ * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
+ * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
+ * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
+ * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
+ * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
+ * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
+ * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
+ * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
+ * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
+ * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
+ * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
+ * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
+ * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
+ * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
+ * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
+ * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
+ * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
+ * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
+ * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
+ * @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
* to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
@@ -441,208 +485,208 @@ hb_language_get_default (void);
*
**/
-/* https://unicode.org/iso15924/ */
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
-/* Unicode Character Database property: Script (sc) */
typedef enum
{
- /*1.1*/ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'),
- /*1.1*/ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'),
- /*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'),
-
- /*1.1*/ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'),
- /*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'),
- /*1.1*/ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'),
- /*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'),
- /*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'),
- /*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'),
- /*1.1*/ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'),
- /*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'),
- /*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'),
- /*1.1*/ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'),
- /*1.1*/ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'),
- /*1.1*/ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'),
- /*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'),
- /*1.1*/ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'),
- /*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'),
- /*1.1*/ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'),
- /*1.1*/ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'),
- /*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'),
- /*1.1*/ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'),
- /*1.1*/ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'),
- /*1.1*/ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'),
- /*1.1*/ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'),
-
- /*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'),
-
- /*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'),
- /*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'),
- /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'),
- /*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'),
- /*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'),
- /*3.0*/ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'),
- /*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'),
- /*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'),
- /*3.0*/ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'),
- /*3.0*/ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'),
- /*3.0*/ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'),
- /*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'),
- /*3.0*/ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'),
- /*3.0*/ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'),
-
- /*3.1*/ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'),
- /*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'),
- /*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'),
-
- /*3.2*/ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'),
- /*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'),
- /*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'),
- /*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'),
-
- /*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'),
- /*4.0*/ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'),
- /*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'),
- /*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'),
- /*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'),
- /*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'),
- /*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'),
-
- /*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'),
- /*4.1*/ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'),
- /*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'),
- /*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'),
- /*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'),
- /*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'),
- /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'),
- /*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'),
-
- /*5.0*/ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'),
- /*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'),
- /*5.0*/ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'),
- /*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'),
- /*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'),
-
- /*5.1*/ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'),
- /*5.1*/ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'),
- /*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'),
- /*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'),
- /*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'),
- /*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'),
- /*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'),
- /*5.1*/ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'),
- /*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'),
- /*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'),
- /*5.1*/ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'),
-
- /*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'),
- /*5.2*/ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'),
- /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'),
- /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'),
- /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'),
- /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'),
- /*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'),
- /*5.2*/ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'),
- /*5.2*/ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'),
- /*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'),
- /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'),
- /*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'),
- /*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'),
- /*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'),
- /*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'),
-
- /*6.0*/ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'),
- /*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'),
- /*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'),
-
- /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'),
- /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'),
- /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'),
- /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'),
- /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'),
- /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
- /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
+ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/
+ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/
+ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/
+
+ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/
+ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/
+ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/
+ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/
+ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/
+ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/
+ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/
+ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/
+ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/
+ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/
+ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/
+ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/
+ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/
+ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/
+ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/
+ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/
+ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/
+ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/
+ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/
+ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/
+ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/
+ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/
+
+ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/
+
+ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/
+ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/
+ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/
+ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/
+ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/
+ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/
+ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/
+ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/
+ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/
+ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/
+ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/
+ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/
+ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/
+ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/
+
+ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/
+ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/
+ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/
+
+ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/
+ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/
+ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/
+ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/
+
+ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/
+ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/
+ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/
+ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/
+ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/
+ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/
+ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/
+
+ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/
+ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/
+ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/
+ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/
+ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/
+ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/
+ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/
+ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/
+
+ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/
+ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/
+ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/
+ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/
+ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/
+
+ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/
+ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/
+ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/
+ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/
+ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/
+ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/
+ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/
+ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/
+ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/
+ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/
+ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/
+
+ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/
+ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/
+ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/
+ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/
+ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/
+ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/
+ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/
+ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/
+ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/
+ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/
+ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/
+ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/
+ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/
+ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/
+ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/
+
+ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/
+ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/
+ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/
+
+ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/
+ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/
+ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/
+ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/
+ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/
+ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/
+ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/
/*
* Since: 0.9.30
*/
- /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
- /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
- /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
- /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'),
- /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'),
- /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'),
- /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'),
- /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'),
- /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'),
- /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'),
- /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'),
- /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'),
- /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'),
- /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'),
- /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'),
- /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'),
- /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'),
- /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'),
- /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'),
- /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'),
- /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'),
- /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
- /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
-
- /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
- /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
- /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
- /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
- /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
- /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
+ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/
+ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/
+ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/
+ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/
+ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/
+ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/
+ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/
+ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/
+ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/
+ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/
+ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/
+ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/
+ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/
+ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/
+ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/
+ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/
+ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/
+ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/
+ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/
+ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/
+ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/
+ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/
+ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/
+
+ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/
+ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/
+ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/
+ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/
+ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/
+ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/
/*
* Since 1.3.0
*/
- /*9.0*/ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'),
- /*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'),
- /*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'),
- /*9.0*/ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'),
- /*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'),
- /*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'),
+ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/
+ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/
+ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/
+ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/
+ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/
+ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/
/*
* Since 1.6.0
*/
- /*10.0*/HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'),
- /*10.0*/HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'),
- /*10.0*/HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'),
- /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'),
+ HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/
+ HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/
+ HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/
+ HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/
/*
* Since 1.8.0
*/
- /*11.0*/HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'),
- /*11.0*/HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'),
- /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'),
- /*11.0*/HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'),
- /*11.0*/HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'),
- /*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
- /*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
+ HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/
+ HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/
+ HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/
+ HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/
+ HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/
+ HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/
+ HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/
/*
* Since 2.4.0
*/
- /*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
- /*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
- /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
- /*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
+ HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/
+ HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/
+ HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/
+ HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/
/*
* Since 2.6.7
*/
- /*13.0*/HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'),
- /*13.0*/HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'),
- /*13.0*/HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'),
- /*13.0*/HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'),
+ HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/
+ HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/
+ HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
+ HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
/* No script set. */
- HB_SCRIPT_INVALID = HB_TAG_NONE,
+ HB_SCRIPT_INVALID = HB_TAG_NONE,
+
+ /*< private >*/
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. We have two, for historical reasons.
@@ -687,19 +731,33 @@ typedef struct hb_user_data_key_t {
char unused;
} hb_user_data_key_t;
+/**
+ * hb_destroy_func_t:
+ * @user_data: the data to be destroyed
+ *
+ * A virtual method for destroy user-data callbacks.
+ *
+ */
typedef void (*hb_destroy_func_t) (void *user_data);
/* Font features and variations. */
/**
- * HB_FEATURE_GLOBAL_START
+ * HB_FEATURE_GLOBAL_START:
+ *
+ * Special setting for #hb_feature_t.start to apply the feature from the start
+ * of the buffer.
*
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_START 0
+
/**
- * HB_FEATURE_GLOBAL_END
+ * HB_FEATURE_GLOBAL_END:
+ *
+ * Special setting for #hb_feature_t.end to apply the feature from to the end
+ * of the buffer.
*
* Since: 2.0.0
*/
@@ -717,7 +775,7 @@ typedef void (*hb_destroy_func_t) (void *user_data);
* The #hb_feature_t is the structure that holds information about requested
* feature application. The feature will be applied with the given value to all
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
- * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
+ * Setting start to #HB_FEATURE_GLOBAL_START and end to #HB_FEATURE_GLOBAL_END
* specifies that the feature always applies to the entire buffer.
*/
typedef struct hb_feature_t {
@@ -741,8 +799,8 @@ hb_feature_to_string (hb_feature_t *feature,
* @value: The value of the variation axis
*
* Data type for holding variation data. Registered OpenType
- * variation-axis tags are listed at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg
+ * variation-axis tags are listed in
+ * [OpenType Axis Tag Registry](https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg).
*
* Since: 1.4.2
*/
@@ -769,6 +827,17 @@ hb_variation_to_string (hb_variation_t *variation,
*/
typedef uint32_t hb_color_t;
+/**
+ * HB_COLOR:
+ * @b: blue channel value
+ * @g: green channel value
+ * @r: red channel value
+ * @a: alpha channel value
+ *
+ * Constructs an #hb_color_t from four integers.
+ *
+ * Since: 2.1.0
+ */
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
HB_EXTERN uint8_t
diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc
index 7b6b2bd5ef..461bd20e65 100644
--- a/thirdparty/harfbuzz/src/hb-coretext.cc
+++ b/thirdparty/harfbuzz/src/hb-coretext.cc
@@ -34,7 +34,6 @@
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
-#include <math.h>
/**
@@ -190,7 +189,10 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
+#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
@@ -346,7 +348,7 @@ retry:
const hb_coretext_font_data_t *data = font->data.coretext;
if (unlikely (!data)) return nullptr;
- if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
+ if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5)
{
/* XXX-MT-bug
* Note that evaluating condition above can be dangerous if another thread
@@ -402,7 +404,7 @@ hb_coretext_font_create (CTFontRef ct_font)
}
/**
- * hb_coretext_face_get_ct_font:
+ * hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
@@ -858,7 +860,7 @@ resize_and_retry:
buffer->len = 0;
uint32_t status_and = ~0, status_or = 0;
- double advances_so_far = 0;
+ CGFloat advances_so_far = 0;
/* For right-to-left runs, CoreText returns the glyphs positioned such that
* any trailing whitespace is to the left of (0,0). Adjust coordinate system
* to fix for that. Test with any RTL string with trailing spaces.
@@ -880,10 +882,10 @@ resize_and_retry:
status_or |= run_status;
status_and &= run_status;
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
- double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
+ CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
run_advance = -run_advance;
- DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+ DEBUG_MSG (CORETEXT, run, "Run advance: %g", (double) run_advance);
/* CoreText does automatic font fallback (AKA "cascading") for characters
* not supported by the requested font, and provides no way to turn it off,
@@ -1062,7 +1064,7 @@ resize_and_retry:
hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
for (unsigned int j = 0; j < num_glyphs; j++)
{
- double advance;
+ CGFloat advance;
if (likely (j + 1 < num_glyphs))
advance = positions[j + 1].x - positions[j].x;
else /* last glyph */
@@ -1078,7 +1080,7 @@ resize_and_retry:
hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
for (unsigned int j = 0; j < num_glyphs; j++)
{
- double advance;
+ CGFloat advance;
if (likely (j + 1 < num_glyphs))
advance = positions[j + 1].y - positions[j].y;
else /* last glyph */
diff --git a/thirdparty/harfbuzz/src/hb-deprecated.h b/thirdparty/harfbuzz/src/hb-deprecated.h
index 43f89a4c4e..5f19125789 100644
--- a/thirdparty/harfbuzz/src/hb-deprecated.h
+++ b/thirdparty/harfbuzz/src/hb-deprecated.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -53,11 +53,50 @@ HB_BEGIN_DECLS
#ifndef HB_DISABLE_DEPRECATED
+/**
+ * HB_SCRIPT_CANADIAN_ABORIGINAL:
+ *
+ * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
+/**
+ * HB_BUFFER_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
+/**
+ * HB_BUFFER_SERIALIZE_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_SERIALIZE_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+/**
+ * hb_font_get_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the glyph ID for a specified Unicode code point
+ * font, with an optional variation selector.
+ *
+ * Return value: %true if data found, %false otherwise
+ * Deprecated: 1.2.3
+ *
+ **/
typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
@@ -73,6 +112,11 @@ hb_set_invert (hb_set_t *set);
/**
* hb_unicode_eastasian_width_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
*
* Deprecated: 2.0.0
*/
@@ -82,12 +126,12 @@ typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t
/**
* hb_unicode_funcs_set_eastasian_width_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: a Unicode-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- *
+ * Sets the implementation function for #hb_unicode_eastasian_width_func_t.
*
* Since: 0.9.2
* Deprecated: 2.0.0
@@ -99,6 +143,10 @@ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
/**
* hb_unicode_eastasian_width:
+ * @ufuncs: a Unicode-function structure
+ * @unicode: The code point to query
+ *
+ * Don't use. Not used by HarfBuzz.
*
* Since: 0.9.2
* Deprecated: 2.0.0
@@ -112,7 +160,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
* hb_unicode_decompose_compatibility_func_t:
* @ufuncs: a Unicode function structure
* @u: codepoint to decompose
- * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @decomposed: address of codepoint array (of length #HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
* @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
*
* Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
@@ -120,7 +168,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
*
* If @u has no compatibility decomposition, zero should be returned.
*
- * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * The Unicode standard guarantees that a buffer of length #HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
* compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations
* of this function type must ensure that they do not write past the provided array.
*
@@ -144,10 +192,12 @@ typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_
/**
* hb_unicode_funcs_set_decompose_compatibility_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_unicode_decompose_compatibility_func_t.
*
*
*
@@ -165,16 +215,25 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *decomposed);
+/**
+ * hb_font_get_glyph_v_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for vertical text segments.
+ *
+ **/
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
/**
* hb_font_funcs_set_glyph_v_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- *
+ * Sets the implementation function for #hb_font_get_glyph_v_kerning_func_t.
*
* Since: 0.9.2
* Deprecated: 2.0.0
diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc
index 92c956c032..a07302159c 100644
--- a/thirdparty/harfbuzz/src/hb-directwrite.cc
+++ b/thirdparty/harfbuzz/src/hb-directwrite.cc
@@ -957,6 +957,8 @@ _hb_directwrite_font_release (void *data)
* hb_directwrite_face_create:
* @font_face: a DirectWrite IDWriteFontFace object.
*
+ * Constructs a new face object from the specified DirectWrite IDWriteFontFace.
+ *
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.4.0
@@ -974,6 +976,8 @@ hb_directwrite_face_create (IDWriteFontFace *font_face)
* hb_directwrite_face_get_font_face:
* @face: a #hb_face_t object
*
+* Gets the DirectWrite IDWriteFontFace associated with @face.
+*
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
*
* Since: 2.5.0
diff --git a/thirdparty/harfbuzz/src/hb-dispatch.hh b/thirdparty/harfbuzz/src/hb-dispatch.hh
index 7eace86e54..4b2b65a8de 100644
--- a/thirdparty/harfbuzz/src/hb-dispatch.hh
+++ b/thirdparty/harfbuzz/src/hb-dispatch.hh
@@ -38,7 +38,6 @@
template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
struct hb_dispatch_context_t
{
- hb_dispatch_context_t () : debug_depth (0) {}
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
const Context* thiz () const { return static_cast<const Context *> (this); }
@@ -54,7 +53,7 @@ struct hb_dispatch_context_t
{ return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
- unsigned debug_depth;
+ unsigned debug_depth = 0;
};
diff --git a/thirdparty/harfbuzz/src/hb-draw.h b/thirdparty/harfbuzz/src/hb-draw.h
index 98eccf4c0c..bddc876399 100644
--- a/thirdparty/harfbuzz/src/hb-draw.h
+++ b/thirdparty/harfbuzz/src/hb-draw.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 33a788e7c5..61bd4af7b1 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -89,8 +89,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
nullptr, /* destroy */
0, /* index */
- HB_ATOMIC_INT_INIT (1000), /* upem */
- HB_ATOMIC_INT_INIT (0), /* num_glyphs */
+ 1000, /* upem */
+ 0, /* num_glyphs */
/* Zero for the rest is fine. */
};
@@ -100,7 +100,7 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
* hb_face_create_for_tables:
* @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
* @user_data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
*
* Variant of hb_face_create(), built for those cases where it is more
* convenient to provide data for individual tables instead of the whole font
@@ -235,7 +235,7 @@ hb_face_create (hb_blob_t *blob,
*
* Fetches the singleton empty face object.
*
- * Return value: (transfer full) The empty face object
+ * Return value: (transfer full): The empty face object
*
* Since: 0.9.2
**/
@@ -299,7 +299,7 @@ hb_face_destroy (hb_face_t *face)
* @face: A face object
* @key: The user-data key to set
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given face object.
@@ -360,7 +360,7 @@ hb_face_make_immutable (hb_face_t *face)
*
* Tests whether the given face object is immutable.
*
- * Return value: True is @face is immutable, false otherwise
+ * Return value: %true is @face is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -756,7 +756,7 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
- if (data->tables.in_error())
+ if (unlikely (data->tables.in_error()))
return false;
entry->tag = tag;
diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h
index 3b18f7eef9..6ef2f8b886 100644
--- a/thirdparty/harfbuzz/src/hb-face.h
+++ b/thirdparty/harfbuzz/src/hb-face.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -58,6 +58,19 @@ HB_EXTERN hb_face_t *
hb_face_create (hb_blob_t *blob,
unsigned int index);
+/**
+ * hb_reference_table_func_t:
+ * @face: an #hb_face_t to reference table for
+ * @tag: the tag of the table to reference
+ * @user_data: User data pointer passed by the caller
+ *
+ * Callback function for hb_face_create_for_tables().
+ *
+ * Return value: (transfer full): A pointer to the @tag table within @face
+ *
+ * Since: 0.9.2
+ */
+
typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
/* calls destroy() when not needing user_data anymore */
diff --git a/thirdparty/harfbuzz/src/hb-face.hh b/thirdparty/harfbuzz/src/hb-face.hh
index f1b472ccf3..765f272858 100644
--- a/thirdparty/harfbuzz/src/hb-face.hh
+++ b/thirdparty/harfbuzz/src/hb-face.hh
@@ -81,7 +81,7 @@ struct hb_face_t
return blob;
}
- HB_PURE_FUNC unsigned int get_upem () const
+ unsigned int get_upem () const
{
unsigned int ret = upem.get_relaxed ();
if (unlikely (!ret))
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index 5c8357ff28..37a0e7fe85 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -628,7 +628,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
* @ffuncs: The font-functions structure
* @key: The user-data key to set
* @data: A pointer to the user data set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified font-functions structure.
@@ -690,7 +690,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
*
* Tests whether a font-functions structure is immutable.
*
- * Return value: %true if @ffuncs is immutable, false otherwise
+ * Return value: %true if @ffuncs is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -753,10 +753,10 @@ hb_font_t::has_func (unsigned int i)
* @font: #hb_font_t to work upon
* @extents: (out): The font extents retrieved
*
- * Fetches the extents for a specified font, in horizontal
+ * Fetches the extents for a specified font, for horizontal
* text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.1.3
**/
@@ -772,10 +772,10 @@ hb_font_get_h_extents (hb_font_t *font,
* @font: #hb_font_t to work upon
* @extents: (out): The font extents retrieved
*
- * Fetches the extents for a specified font, in vertical
+ * Fetches the extents for a specified font, for vertical
* text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.1.3
**/
@@ -790,7 +790,7 @@ hb_font_get_v_extents (hb_font_t *font,
* hb_font_get_glyph:
* @font: #hb_font_t to work upon
* @unicode: The Unicode code point to query
- * @variation_selector: (optional): A variation-selector code point
+ * @variation_selector: A variation-selector code point
* @glyph: (out): The glyph ID retrieved
*
* Fetches the glyph ID for a Unicode code point in the specified
@@ -799,7 +799,7 @@ hb_font_get_v_extents (hb_font_t *font,
* If @variation_selector is 0, calls hb_font_get_nominal_glyph();
* otherwise calls hb_font_get_variation_glyph().
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -827,7 +827,7 @@ hb_font_get_glyph (hb_font_t *font,
* for code points modified by variation selectors. For variation-selector
* support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.2.3
**/
@@ -841,11 +841,17 @@ hb_font_get_nominal_glyph (hb_font_t *font,
/**
* hb_font_get_nominal_glyphs:
- * @font: a font.
- *
+ * @font: #hb_font_t to work upon
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @glyph_stride: The stride between successive glyph IDs
*
+ * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
+ * IDs must be returned in a #hb_codepoint_t output parameter.
*
- * Return value:
+ * Return value: the number of code points processed
*
* Since: 2.6.3
**/
@@ -873,7 +879,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
* by the specified variation-selector code point, in the specified
* font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.2.3
**/
@@ -931,7 +937,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
* @first_glyph: The first glyph ID to query
* @glyph_stride: The stride between successive glyph IDs
* @first_advance: (out): The first advance retrieved
- * @advance_stride: (out): The stride between successive advances
+ * @advance_stride: The stride between successive advances
*
* Fetches the advances for a sequence of glyph IDs in the specified
* font, for horizontal text segments.
@@ -983,7 +989,7 @@ hb_font_get_glyph_v_advances (hb_font_t* font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for horizontal text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1006,7 +1012,7 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for vertical text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1026,7 +1032,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
* @right_glyph: The glyph ID of the right glyph in the glyph pair
*
* Fetches the kerning-adjustment value for a glyph-pair in
- * the specified font, in horizontal text segments.
+ * the specified font, for horizontal text segments.
*
* <note>It handles legacy kerning only (as returned by the corresponding
* #hb_font_funcs_t function).</note>
@@ -1051,7 +1057,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
* @bottom_glyph: The glyph ID of the bottom glyph in the glyph pair
*
* Fetches the kerning-adjustment value for a glyph-pair in
- * the specified font, in vertical text segments.
+ * the specified font, for vertical text segments.
*
* <note>It handles legacy kerning only (as returned by the corresponding
* #hb_font_funcs_t function).</note>
@@ -1079,7 +1085,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
* Fetches the #hb_glyph_extents_t data for a glyph ID
* in the specified font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1102,7 +1108,7 @@ hb_font_get_glyph_extents (hb_font_t *font,
* Fetches the (x,y) coordinates of a specified contour-point index
* in the specified glyph, within the specified font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1125,7 +1131,7 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
*
* Fetches the glyph-name string for a glyph ID in the specified @font.
*
- * Return value: %true if data found, zero otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1149,7 +1155,7 @@ hb_font_get_glyph_name (hb_font_t *font,
*
* <note>Note: @len == -1 means the name string is null-terminated.</note>
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1169,7 +1175,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* hb_font_get_extents_for_direction:
* @font: #hb_font_t to work upon
* @direction: The direction of the text segment
- * @extents: (out): The #hb_glyph_extents_t retrieved
+ * @extents: (out): The #hb_font_extents_t retrieved
*
* Fetches the extents for a font in a text segment of the
* specified direction.
@@ -1364,7 +1370,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1393,7 +1399,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1444,7 +1450,7 @@ hb_font_glyph_to_string (hb_font_t *font,
*
* <note>Note: @len == -1 means the string is null-terminated.</note>
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1664,12 +1670,12 @@ hb_font_destroy (hb_font_t *font)
* @font: #hb_font_t to work upon
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified font object.
*
- * Return value:
+ * Return value: %true if success, %false otherwise
*
* Since: 0.9.2
**/
@@ -1728,7 +1734,7 @@ hb_font_make_immutable (hb_font_t *font)
*
* Tests whether a font object is immutable.
*
- * Return value: %true if @font is immutable, false otherwise
+ * Return value: %true if @font is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -1828,9 +1834,9 @@ hb_font_get_face (hb_font_t *font)
/**
* hb_font_set_funcs:
* @font: #hb_font_t to work upon
- * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @klass: (closure font_data) (destroy destroy) (scope notified): The font-functions structure.
* @font_data: Data to attach to @font
- * @destroy: (optional): The function to call when @font_data is not needed anymore
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
*
* Replaces the font-functions structure attached to a font, updating
* the font's user-data with @font-data and the @destroy callback.
@@ -1867,7 +1873,7 @@ hb_font_set_funcs (hb_font_t *font,
* hb_font_set_funcs_data:
* @font: #hb_font_t to work upon
* @font_data: (destroy destroy) (scope notified): Data to attach to @font
- * @destroy: (optional): The function to call when @font_data is not needed anymore
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
*
* Replaces the user data attached to a font, updating the font's
* @destroy callback.
@@ -2212,10 +2218,14 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
#ifdef HB_EXPERIMENTAL_API
/**
* hb_font_get_var_coords_design:
+ * @font: #hb_font_t to work upon
+ * @length: (out): number of coordinates
*
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
+ * Return value: coordinates array
+ *
* Since: EXPERIMENTAL
*/
const float *
@@ -2319,7 +2329,7 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font,
* @ffuncs: The font-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): callback function
* @user_data: data to pass to @func
- * @destroy: (optional): function to call when @user_data is not needed anymore
+ * @destroy: (nullable): function to call when @user_data is not needed anymore
*
* Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and
* hb_font_funcs_set_variation_glyph_func() instead.
diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h
index 05f6c03f47..15dc126523 100644
--- a/thirdparty/harfbuzz/src/hb-font.h
+++ b/thirdparty/harfbuzz/src/hb-font.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -37,7 +37,12 @@
HB_BEGIN_DECLS
-
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
typedef struct hb_font_t hb_font_t;
@@ -141,6 +146,16 @@ typedef struct hb_glyph_extents_t {
/* func types */
+/**
+ * hb_font_get_font_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @extents: (out): The font extents retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the extents for a font.
+ *
+ **/
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
hb_font_extents_t *extents,
void *user_data);
@@ -150,7 +165,7 @@ typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *fon
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
- * This method should retrieve the extents for a font, in horizontal-direction
+ * This method should retrieve the extents for a font, for horizontal-direction
* text segments. Extents must be returned in an #hb_glyph_extents output
* parameter.
*
@@ -162,7 +177,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
- * This method should retrieve the extents for a font, in vertical-direction
+ * This method should retrieve the extents for a font, for vertical-direction
* text segments. Extents must be returned in an #hb_glyph_extents output
* parameter.
*
@@ -172,12 +187,19 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
/**
* hb_font_get_nominal_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the nominal glyph ID for a specified Unicode code
* point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode,
@@ -186,6 +208,12 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
/**
* hb_font_get_variation_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -193,6 +221,8 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
* followed by a specified Variation Selector code point. Glyph IDs must be
* returned in a #hb_codepoint_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@@ -202,12 +232,22 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *
/**
* hb_font_get_nominal_glyphs_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @glyph_stride: The stride between successive glyph IDs
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the nominal glyph IDs for a sequence of
* Unicode code points. Glyph IDs must be returned in a #hb_codepoint_t
* output parameter.
+ *
+ * Return value: the number of code points processed
*
**/
typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
@@ -220,12 +260,18 @@ typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void
/**
* hb_font_get_glyph_advance_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the advance for a specified glyph. The
* method must return an #hb_position_t.
*
+ * Return value: The advance of @glyph within @font
+ *
**/
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -257,6 +303,14 @@ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
/**
* hb_font_get_glyph_advances_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: The stride between successive advances
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -295,12 +349,20 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
/**
* hb_font_get_glyph_origin_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @x: (out): The X coordinate of the origin
+ * @y: (out): The Y coordinate of the origin
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
* origin for a glyph. Each coordinate must be returned in an #hb_position_t
* output parameter.
+ *
+ * Return value: %true if data found, %false otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -314,7 +376,7 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
- * origin for a glyph, in horizontal-direction text segments. Each
+ * origin for a glyph, for horizontal-direction text segments. Each
* coordinate must be returned in an #hb_position_t output parameter.
*
**/
@@ -326,25 +388,53 @@ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
- * origin for a glyph, in vertical-direction text segments. Each coordinate
+ * origin for a glyph, for vertical-direction text segments. Each coordinate
* must be returned in an #hb_position_t output parameter.
*
**/
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
+/**
+ * hb_font_get_glyph_kerning_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @first_glyph: The glyph ID of the first glyph in the glyph pair
+ * @second_glyph: The glyph ID of the second glyph in the glyph pair
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
+/**
+ * hb_font_get_glyph_h_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
/**
* hb_font_get_glyph_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @extents: (out): The #hb_glyph_extents_t retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the extents for a specified glyph. Extents must be
* returned in an #hb_glyph_extents output parameter.
+ *
+ * Return value: %true if data found, %false otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -354,6 +444,13 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
/**
* hb_font_get_glyph_contour_point_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @point_index: The contour-point index to query
+ * @x: (out): The X value retrieved for the contour point
+ * @y: (out): The Y value retrieved for the contour point
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -361,6 +458,8 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
* specified contour point in a glyph. Each coordinate must be returned as
* an #hb_position_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph, unsigned int point_index,
@@ -370,12 +469,20 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
/**
* hb_font_get_glyph_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @name: (out) (array length=size): Name string retrieved for the glyph ID
+ * @size: Length of the glyph-name string retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the glyph name that corresponds to a
* glyph ID. The name should be returned in a string output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -384,12 +491,20 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
/**
* hb_font_get_glyph_from_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @name: (array length=len): The name string to query
+ * @len: The length of the name queried
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the glyph ID that corresponds to a glyph-name
* string.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
const char *name, int len, /* -1 means nul-terminated */
@@ -404,7 +519,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_font_h_extents_func_t.
*
@@ -420,7 +535,7 @@ hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_font_v_extents_func_t.
*
@@ -436,7 +551,7 @@ hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_nominal_glyph_func_t.
*
@@ -452,7 +567,7 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_nominal_glyphs_func_t.
*
@@ -468,7 +583,7 @@ hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_variation_glyph_func_t.
*
@@ -484,7 +599,7 @@ hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_advance_func_t.
*
@@ -500,7 +615,7 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_advance_func_t.
*
@@ -516,7 +631,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_advances_func_t.
*
@@ -532,7 +647,7 @@ hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_advances_func_t.
*
@@ -548,7 +663,7 @@ hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_origin_func_t.
*
@@ -564,7 +679,7 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_origin_func_t.
*
@@ -577,12 +692,12 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
/**
* hb_font_funcs_set_glyph_h_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
+ * Sets the implementation function for #hb_font_get_glyph_h_kerning_func_t.
*
* Since: 0.9.2
**/
@@ -596,7 +711,7 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_extents_func_t.
*
@@ -612,7 +727,7 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_contour_point_func_t.
*
@@ -628,7 +743,7 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_name_func_t.
*
@@ -644,7 +759,7 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_from_name_func_t.
*
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index ab7d6146ce..b82c1a67bd 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -84,7 +84,7 @@ struct hb_ft_font_t
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
- mutable hb_atomic_int_t cached_x_scale;
+ mutable int cached_x_scale;
mutable hb_advance_cache_t advance_cache;
};
@@ -101,7 +101,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
- ft_font->cached_x_scale.set_relaxed (0);
+ ft_font->cached_x_scale = 0;
ft_font->advance_cache.init ();
return ft_font;
@@ -179,13 +179,13 @@ hb_ft_font_get_load_flags (hb_font_t *font)
}
/**
- * hb_ft_get_face:
+ * hb_ft_font_get_face:
* @font: #hb_font_t to work upon
*
* Fetches the FT_Face associated with the specified #hb_font_t
* font object.
*
- * Return value: the FT_Face found
+ * Return value: (nullable): the FT_Face found or %NULL
*
* Since: 0.9.2
**/
@@ -202,11 +202,12 @@ hb_ft_font_get_face (hb_font_t *font)
/**
* hb_ft_font_lock_face:
- * @font:
- *
+ * @font: #hb_font_t to work upon
*
+ * Gets the FT_Face associated with @font, This face will be kept around until
+ * you call hb_ft_font_unlock_face().
*
- * Return value:
+ * Return value: (nullable): the FT_Face associated with @font or %NULL
* Since: 2.6.5
**/
FT_Face
@@ -224,11 +225,10 @@ hb_ft_font_lock_face (hb_font_t *font)
/**
* hb_ft_font_unlock_face:
- * @font:
- *
+ * @font: #hb_font_t to work upon
*
+ * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
*
- * Return value:
* Since: 2.6.5
**/
void
@@ -335,10 +335,10 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
int load_flags = ft_font->load_flags;
int mult = font->x_scale < 0 ? -1 : +1;
- if (font->x_scale != ft_font->cached_x_scale.get ())
+ if (font->x_scale != ft_font->cached_x_scale)
{
ft_font->advance_cache.clear ();
- ft_font->cached_x_scale.set (font->x_scale);
+ ft_font->cached_x_scale = font->x_scale;
}
for (unsigned int i = 0; i < count; i++)
@@ -661,7 +661,7 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
/**
* hb_ft_face_create:
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
- * @destroy: (optional): A callback to call when the face object is not needed anymore
+ * @destroy: (nullable): A callback to call when the face object is not needed anymore
*
* Creates an #hb_face_t face object from the specified FT_Face.
*
@@ -771,13 +771,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
/**
* hb_ft_font_create:
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
- * @destroy: (optional): A callback to call when the font object is not needed anymore
+ * @destroy: (nullable): A callback to call when the font object is not needed anymore
*
* Creates an #hb_font_t font object from the specified FT_Face.
*
* <note>Note: You must set the face size on @ft_face before calling
- * hb_ft_font_create() on it. Otherwise, HarfBuzz will not pick up
- * the face size.</note>
+ * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
+ * access `size` member of FT_Face unconditionally.</note>
*
* This variant of the function does not provide any life-cycle management.
*
@@ -814,7 +814,7 @@ hb_ft_font_create (FT_Face ft_face,
}
/**
- * hb_ft_font_has_changed:
+ * hb_ft_font_changed:
* @font: #hb_font_t to work upon
*
* Refreshes the state of @font when the underlying FT_Face has changed.
@@ -884,8 +884,8 @@ hb_ft_font_changed (hb_font_t *font)
* Creates an #hb_font_t font object from the specified FT_Face.
*
* <note>Note: You must set the face size on @ft_face before calling
- * hb_ft_font_create_references() on it. Otherwise, HarfBuzz will not pick up
- * the face size.</note>
+ * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
+ * and will access `size` member of FT_Face unconditionally.</note>
*
* This is the preferred variant of the hb_ft_font_create*
* function family, because it calls FT_Reference_Face() on @ft_face,
diff --git a/thirdparty/harfbuzz/src/hb-gdi.cc b/thirdparty/harfbuzz/src/hb-gdi.cc
index 3a67cef160..dc4659c7f6 100644
--- a/thirdparty/harfbuzz/src/hb-gdi.cc
+++ b/thirdparty/harfbuzz/src/hb-gdi.cc
@@ -70,6 +70,8 @@ fail:
* hb_gdi_face_create:
* @hfont: a HFONT object.
*
+ * Constructs a new face object from the specified GDI HFONT.
+ *
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.6.0
diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.h b/thirdparty/harfbuzz/src/hb-gobject-structs.h
index 6fad8d7019..63467f80df 100644
--- a/thirdparty/harfbuzz/src/hb-gobject-structs.h
+++ b/thirdparty/harfbuzz/src/hb-gobject-structs.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_GOBJECT_H_IN
+#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-gobject.h> instead."
#endif
@@ -40,47 +40,22 @@ HB_BEGIN_DECLS
/* Object types */
-/**
- * hb_gobject_blob_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_blob_get_type (void);
#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
-/**
- * hb_gobject_buffer_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_buffer_get_type (void);
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
-/**
- * hb_gobject_face_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
-/**
- * hb_gobject_font_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_font_get_type (void);
#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
-/**
- * hb_gobject_font_funcs_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_font_funcs_get_type (void);
#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
@@ -97,11 +72,6 @@ HB_EXTERN GType
hb_gobject_shape_plan_get_type (void);
#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
-/**
- * hb_gobject_unicode_funcs_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_unicode_funcs_get_type (void);
#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc
index d8a72dc2f1..9dafe654c8 100644
--- a/thirdparty/harfbuzz/src/hb-graphite2.cc
+++ b/thirdparty/harfbuzz/src/hb-graphite2.cc
@@ -195,6 +195,11 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_graphite2_font_get_gr_font:
+ * @font: An #hb_font_t
+ *
+ * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ *
+ * Return value: (nullable): Graphite2 font associated with @font.
*
* Since: 0.9.10
* Deprecated: 1.4.2
@@ -284,7 +289,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
return true;
}
- buffer->ensure (glyph_count);
+ (void) buffer->ensure (glyph_count);
scratch = buffer->get_scratch_buffer (&scratch_size);
while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh
index 981c5c218c..f7018150e4 100644
--- a/thirdparty/harfbuzz/src/hb-iter.hh
+++ b/thirdparty/harfbuzz/src/hb-iter.hh
@@ -922,7 +922,7 @@ HB_FUNCOBJ (hb_none);
template <typename C, typename V,
hb_requires (hb_is_iterable (C))>
inline void
-hb_fill (C& c, const V &v)
+hb_fill (C&& c, const V &v)
{
for (auto i = hb_iter (c); i; i++)
*i = v;
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index 54bc60d4c8..3bd5a979b0 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -80,6 +80,11 @@ static inline Type& StructAfter(TObject &X)
* Size checking
*/
+/* Size signifying variable-sized array */
+#ifndef HB_VAR_ARRAY
+#define HB_VAR_ARRAY 1
+#endif
+
/* Check _assertion in a method environment */
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
void _instance_assertion_on_line_##_line () const \
diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc
index f898bd8f92..f115da2bb8 100644
--- a/thirdparty/harfbuzz/src/hb-map.cc
+++ b/thirdparty/harfbuzz/src/hb-map.cc
@@ -117,7 +117,7 @@ hb_map_destroy (hb_map_t *map)
* @map: A map
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified map.
@@ -162,7 +162,7 @@ hb_map_get_user_data (hb_map_t *map,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, false otherwise
+ * Return value: %true if allocation succeeded, %false otherwise
*
* Since: 1.7.7
**/
@@ -230,7 +230,7 @@ hb_map_del (hb_map_t *map,
*
* Tests whether @key is an element of @map.
*
- * Return value: %true if @key is found in @map, false otherwise
+ * Return value: %true if @key is found in @map, %false otherwise
*
* Since: 1.7.7
**/
@@ -253,6 +253,9 @@ hb_map_has (const hb_map_t *map,
void
hb_map_clear (hb_map_t *map)
{
+ if (unlikely (hb_object_is_immutable (map)))
+ return;
+
return map->clear ();
}
diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h
index 0c19ac8fb5..6a45a7bdd5 100644
--- a/thirdparty/harfbuzz/src/hb-map.h
+++ b/thirdparty/harfbuzz/src/hb-map.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,7 +36,11 @@
HB_BEGIN_DECLS
-/*
+/**
+ * HB_MAP_VALUE_INVALID:
+ *
+ * Unset #hb_map_t value.
+ *
* Since: 1.7.7
*/
#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh
index 92c1bd67e5..84fe1d549b 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -97,8 +97,6 @@ struct hb_hashmap_t
void reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
successful = true;
clear ();
}
@@ -171,8 +169,6 @@ struct hb_hashmap_t
void clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
if (items)
for (auto &_ : hb_iter (items, mask + 1))
_.clear ();
@@ -181,6 +177,7 @@ struct hb_hashmap_t
}
bool is_empty () const { return population == 0; }
+ explicit operator bool () const { return !is_empty (); }
unsigned int get_population () const { return population; }
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 4c0898b1b7..e40d9fd178 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -49,6 +49,10 @@ template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
using hb_true_type = hb_bool_constant<true>;
using hb_false_type = hb_bool_constant<false>;
+/* Static-assert as expression. */
+template <bool cond> struct static_assert_expr;
+template <> struct static_assert_expr<true> : hb_false_type {};
+#define static_assert_expr(C) static_assert_expr<C>::value
/* Basic type SFINAE. */
@@ -220,6 +224,8 @@ struct hb_reference_wrapper<T&>
};
+/* Type traits */
+
template <typename T>
using hb_is_integral = hb_bool_constant<
hb_is_same (hb_decay<T>, char) ||
@@ -292,6 +298,15 @@ template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigne
#define hb_int_max(T) hb_int_max<T>::value
+/* Class traits. */
+
+#define HB_DELETE_COPY_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
+#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
+ TypeName() = delete; \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
template <typename T, typename>
struct _hb_is_destructible : hb_false_type {};
diff --git a/thirdparty/harfbuzz/src/hb-mutex.hh b/thirdparty/harfbuzz/src/hb-mutex.hh
index 56392d049b..2fc8d7ee58 100644
--- a/thirdparty/harfbuzz/src/hb-mutex.hh
+++ b/thirdparty/harfbuzz/src/hb-mutex.hh
@@ -73,24 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
-# include <sched.h>
-# define HB_SCHED_YIELD() sched_yield ()
-#else
-# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
-#endif
-
-/* This actually is not a totally awful implementation. */
-typedef volatile int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT 0
-#define hb_mutex_impl_init(M) *(M) = 0
-#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
-#define hb_mutex_impl_unlock(M) __sync_lock_release (M)
-#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
-
-
#elif defined(HB_NO_MT)
typedef int hb_mutex_impl_t;
diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh
index 39845a70e7..f3048b1c3e 100644
--- a/thirdparty/harfbuzz/src/hb-object.hh
+++ b/thirdparty/harfbuzz/src/hb-object.hh
@@ -140,9 +140,7 @@ struct hb_lockable_set_t
* Reference-count.
*/
-#define HB_REFERENCE_COUNT_INERT_VALUE 0
-#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
-#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)}
+#define HB_REFERENCE_COUNT_INIT {0}
struct hb_reference_count_t
{
@@ -152,9 +150,9 @@ struct hb_reference_count_t
int get_relaxed () const { return ref_count.get_relaxed (); }
int inc () const { return ref_count.inc (); }
int dec () const { return ref_count.dec (); }
- void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
+ void fini () { ref_count.set_relaxed (-0x0000DEAD); }
- bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
+ bool is_inert () const { return !ref_count.get_relaxed (); }
bool is_valid () const { return ref_count.get_relaxed () > 0; }
};
@@ -197,15 +195,10 @@ struct hb_user_data_array_t
struct hb_object_header_t
{
hb_reference_count_t ref_count;
- mutable hb_atomic_int_t writable;
+ mutable hb_atomic_int_t writable = 0;
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
};
-#define HB_OBJECT_HEADER_STATIC \
- { \
- HB_REFERENCE_COUNT_INIT, \
- HB_ATOMIC_INT_INIT (false), \
- HB_ATOMIC_PTR_INIT (nullptr) \
- }
+#define HB_OBJECT_HEADER_STATIC {}
/*
diff --git a/thirdparty/harfbuzz/src/hb-open-file.hh b/thirdparty/harfbuzz/src/hb-open-file.hh
index ac13dd23c3..54c07ff13c 100644
--- a/thirdparty/harfbuzz/src/hb-open-file.hh
+++ b/thirdparty/harfbuzz/src/hb-open-file.hh
@@ -48,7 +48,7 @@ namespace OT {
*/
struct OpenTypeFontFile;
-struct OffsetTable;
+struct OpenTypeOffsetTable;
struct TTCHeader;
@@ -78,7 +78,7 @@ typedef struct TableRecord
DEFINE_SIZE_STATIC (16);
} OpenTypeTable;
-typedef struct OffsetTable
+typedef struct OpenTypeOffsetTable
{
friend struct OpenTypeFontFile;
@@ -218,7 +218,7 @@ struct TTCHeaderVersion1
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
- LArrayOf<LOffsetTo<OffsetTable>>
+ LArrayOf<LOffsetTo<OpenTypeOffsetTable>>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index 99634b76f0..dc0ae1d989 100644
--- a/thirdparty/harfbuzz/src/hb-open-type.hh
+++ b/thirdparty/harfbuzz/src/hb-open-type.hh
@@ -53,14 +53,19 @@ namespace OT {
*/
/* Integer types in big-endian order and no alignment requirement */
-template <typename Type, unsigned int Size>
+template <typename Type,
+ unsigned int Size = sizeof (Type)>
struct IntType
{
typedef Type type;
- typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
- IntType& operator = (wide_type i) { v = i; return *this; }
- operator wide_type () const { return v; }
+ IntType () = default;
+ explicit constexpr IntType (Type V) : v {V} {}
+ IntType& operator = (Type i) { v = i; return *this; }
+ /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
+ * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
+ operator hb_conditional<hb_is_signed (Type), signed, unsigned> () const { return v; }
+
bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
bool operator != (const IntType &o) const { return !(*this == o); }
@@ -80,14 +85,21 @@ struct IntType
return pb->cmp (*pa);
}
- template <typename Type2>
+ template <typename Type2,
+ hb_enable_if (hb_is_integral (Type2) &&
+ sizeof (Type2) < sizeof (int) &&
+ sizeof (Type) < sizeof (int))>
int cmp (Type2 a) const
{
Type b = v;
- if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
- return (int) a - (int) b;
- else
- return a < b ? -1 : a == b ? 0 : +1;
+ return (int) a - (int) b;
+ }
+ template <typename Type2,
+ hb_enable_if (hb_is_convertible (Type2, Type))>
+ int cmp (Type2 a) const
+ {
+ Type b = v;
+ return a < b ? -1 : a == b ? 0 : +1;
}
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -100,12 +112,12 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
-typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */
-typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */
-typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */
-typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */
+typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
+typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
+typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
+typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
+typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
+typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
* Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
@@ -163,8 +175,8 @@ struct Tag : HBUINT32
{
Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
/* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
- operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
- operator char* () { return reinterpret_cast<char *> (&this->v); }
+ operator const char* () const { return reinterpret_cast<const char *> (this); }
+ operator char* () { return reinterpret_cast<char *> (this); }
public:
DEFINE_SIZE_STATIC (4);
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
index e5286cd792..864a27f458 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -183,7 +183,7 @@ struct CFFIndex
else
{
serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; }));
- for (const byte_str_t &_ : +it)
+ for (const auto &_ : +it)
_.copy (c);
}
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
index 66b9c8c907..3298fa35ae 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
@@ -426,7 +426,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
else
{
extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
- extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
+ extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing;
}
if (bounds.min.y >= bounds.max.y)
{
@@ -436,7 +436,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
else
{
extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
- extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
+ extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing;
}
return true;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
index ac0feeee21..879b7cdb23 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
@@ -127,7 +127,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
else
{
extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
- extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
+ extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing;
}
if (param.min_y >= param.max_y)
{
@@ -137,7 +137,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
else
{
extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
- extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
+ extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing;
}
return true;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index cc48379bb8..878e02ff17 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -95,7 +95,7 @@ struct CmapSubtableFormat4
HBUINT16 *endCode = c->start_embed<HBUINT16> ();
hb_codepoint_t prev_endcp = 0xFFFF;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
{
@@ -131,7 +131,7 @@ struct CmapSubtableFormat4
HBUINT16 *startCode = c->start_embed<HBUINT16> ();
hb_codepoint_t prev_cp = 0xFFFF;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
{
@@ -170,7 +170,7 @@ struct CmapSubtableFormat4
if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
return nullptr;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (_.first == startCode[i])
{
@@ -696,7 +696,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
hb_codepoint_t glyphID = 0;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (startCharCode == 0xFFFF)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
index aaa1c37c64..e285acec3d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
@@ -455,8 +455,8 @@ struct IndexSubtableRecord
unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;
// Set to invalid state to indicate filling glyphs is not yet started.
- if (unlikely (!records->resize (records->length + 1)))
- return_trace (c->serializer->check_success (false));
+ if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
+ return_trace (false);
(*records)[records->length - 1].firstGlyphIndex = 1;
(*records)[records->length - 1].lastGlyphIndex = 0;
@@ -567,8 +567,8 @@ struct IndexSubtableArray
hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
build_lookup (c, bitmap_size_context, &lookup);
- if (unlikely (lookup.in_error ()))
- return c->serializer->check_success (false);
+ if (unlikely (!c->serializer->propagate_error (lookup)))
+ return false;
bitmap_size_context->size = 0;
bitmap_size_context->num_tables = 0;
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
index 92a49bb4f4..e2a1ff4662 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
@@ -214,7 +214,7 @@ struct COLR
if (unlikely (!old_record))
return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
- BaseGlyphRecord new_record;
+ BaseGlyphRecord new_record = {};
new_record.glyphId = new_gid;
new_record.numLayers = old_record->numLayers;
return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
diff --git a/thirdparty/harfbuzz/src/hb-ot-color.cc b/thirdparty/harfbuzz/src/hb-ot-color.cc
index 0e7203a88b..4170b71317 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-color.cc
@@ -37,9 +37,6 @@
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
-#include <stdlib.h>
-#include <string.h>
-
/**
* SECTION:hb-ot-color
@@ -64,7 +61,7 @@
*
* Tests whether a face includes a `CPAL` color-palette table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
@@ -195,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
*
* Tests whether a face includes any `COLR` color layers.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
@@ -242,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
*
* Tests whether a face includes any `SVG` glyph images.
*
- * Return value: true if data found, false otherwise.
+ * Return value: %true if data found, %false otherwise.
*
* Since: 2.1.0
*/
@@ -280,7 +277,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
*
* Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
diff --git a/thirdparty/harfbuzz/src/hb-ot-color.h b/thirdparty/harfbuzz/src/hb-ot-color.h
index 4f37a4386f..c23ce4de44 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color.h
+++ b/thirdparty/harfbuzz/src/hb-ot-color.h
@@ -26,7 +26,7 @@
* Google Author(s): Sascha Brawer, Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -66,6 +66,8 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
* palette is appropriate to use when displaying the font on a dark background such as black.
*
+ * Flags that describe the properties of color palette.
+ *
* Since: 2.1.0
*/
typedef enum { /*< flags >*/
@@ -95,6 +97,8 @@ hb_ot_color_has_layers (hb_face_t *face);
/**
* hb_ot_color_layer_t:
+ * @glyph: the glyph ID of the layer
+ * @color_index: the palette color index of the layer
*
* Pairs of glyph and color index.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-deprecated.h b/thirdparty/harfbuzz/src/hb-ot-deprecated.h
index 2e75deef2d..ce6b6fef11 100644
--- a/thirdparty/harfbuzz/src/hb-ot-deprecated.h
+++ b/thirdparty/harfbuzz/src/hb-ot-deprecated.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -41,6 +41,13 @@ HB_BEGIN_DECLS
/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
+/**
+ * HB_MATH_GLYPH_PART_FLAG_EXTENDER:
+ *
+ * Use #HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER instead.
+ *
+ * Deprecated: 2.5.1
+ */
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
@@ -71,6 +78,8 @@ hb_ot_tag_from_language (hb_language_t language);
/**
* HB_OT_VAR_NO_AXIS_INDEX:
*
+ * Do not use.
+ *
* Since: 1.4.2
* Deprecated: 2.2.0
*/
@@ -78,6 +87,13 @@ hb_ot_tag_from_language (hb_language_t language);
/**
* hb_ot_var_axis_t:
+ * @tag: axis tag
+ * @name_id: axis name identifier
+ * @min_value: minimum value of the axis
+ * @default_value: default value of the axis
+ * @max_value: maximum value of the axis
+ *
+ * Use #hb_ot_var_axis_info_t instead.
*
* Since: 1.4.2
* Deprecated: 2.2.0
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.h b/thirdparty/harfbuzz/src/hb-ot-font.h
index 80eaa54b1a..e7959d1ae2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.h
+++ b/thirdparty/harfbuzz/src/hb-ot-font.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
index 5470bd96da..5352156f02 100644
--- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
@@ -186,7 +186,7 @@ struct glyf
| hb_map (&SubsetGlyph::padded_size)
;
- if (c->serializer->in_error ()) return_trace (false);
+ if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
padded_offsets)));
}
@@ -944,9 +944,9 @@ struct glyf
return;
}
extents->x_bearing = font->em_scalef_x (min_x);
- extents->width = font->em_scalef_x (max_x - min_x);
+ extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
extents->y_bearing = font->em_scalef_y (max_y);
- extents->height = font->em_scalef_y (min_y - max_y);
+ extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
}
protected:
diff --git a/thirdparty/harfbuzz/src/hb-ot-head-table.hh b/thirdparty/harfbuzz/src/hb-ot-head-table.hh
index 5613a96dbf..ac588e3af6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-head-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-head-table.hh
@@ -43,7 +43,7 @@ namespace OT {
struct head
{
- friend struct OffsetTable;
+ friend struct OpenTypeOffsetTable;
static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 6ab950a322..0ba7e3c061 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -1128,7 +1128,7 @@ struct Lookup
out->lookupType = lookupType;
out->lookupFlag = lookupFlag;
- const hb_set_t *glyphset = c->plan->glyphset ();
+ const hb_set_t *glyphset = c->plan->glyphset_gsub ();
unsigned int lookup_type = get_type ();
+ hb_iter (get_subtables <TSubTable> ())
| hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
@@ -1251,8 +1251,9 @@ struct CoverageFormat1
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = glyphArray.len;
+ const HBGlyphID *arr = glyphArray.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (glyphs->has (glyphArray[i]))
+ if (glyphs->has (arr[i]))
return true;
return false;
}
@@ -1356,18 +1357,21 @@ struct CoverageFormat2
bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].intersects (glyphs))
+ /* TODO(iter) Rewrite as dagger. */
+ unsigned count = rangeRecord.len;
+ const RangeRecord *arr = rangeRecord.arrayZ;
+ for (unsigned i = 0; i < count; i++)
+ if (arr[i].intersects (glyphs))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
- unsigned int i;
- unsigned int count = rangeRecord.len;
- for (i = 0; i < count; i++) {
- const RangeRecord &range = rangeRecord[i];
+ /* TODO(iter) Rewrite as dagger. */
+ unsigned count = rangeRecord.len;
+ const RangeRecord *arr = rangeRecord.arrayZ;
+ for (unsigned i = 0; i < count; i++) {
+ const RangeRecord &range = arr[i];
if (range.value <= index &&
index < (unsigned int) range.value + (range.last - range.first) &&
range.intersects (glyphs))
@@ -1502,7 +1506,7 @@ struct Coverage
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -1729,7 +1733,7 @@ struct ClassDefFormat1
hb_map_t *klass_map = nullptr /*OUT*/) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs;
@@ -1784,7 +1788,7 @@ struct ClassDefFormat1
}
template <typename set_t>
- bool collect_class (set_t *glyphs, unsigned int klass) const
+ bool collect_class (set_t *glyphs, unsigned klass) const
{
unsigned int count = classValue.len;
for (unsigned int i = 0; i < count; i++)
@@ -1802,7 +1806,7 @@ struct ClassDefFormat1
if (classValue[iter - start]) return true;
return false;
}
- bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+ bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
unsigned int count = classValue.len;
if (klass == 0)
@@ -1815,8 +1819,12 @@ struct ClassDefFormat1
if (hb_set_next (glyphs, &g)) return true;
/* Fall through. */
}
+ /* TODO Speed up, using set overlap first? */
+ /* TODO(iter) Rewrite as dagger. */
+ HBUINT16 k {klass};
+ const HBUINT16 *arr = classValue.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (classValue[i] == klass && glyphs->has (startGlyph + i))
+ if (arr[i] == k && glyphs->has (startGlyph + i))
return true;
return false;
}
@@ -1898,7 +1906,7 @@ struct ClassDefFormat2
hb_map_t *klass_map = nullptr /*OUT*/) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs;
@@ -1961,11 +1969,14 @@ struct ClassDefFormat2
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].intersects (glyphs))
+ {
+ const auto& range = rangeRecord[i];
+ if (range.intersects (glyphs) && range.value)
return true;
+ }
return false;
}
- bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+ bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
unsigned int count = rangeRecord.len;
if (klass == 0)
@@ -1984,8 +1995,12 @@ struct ClassDefFormat2
return true;
/* Fall through. */
}
+ /* TODO Speed up, using set overlap first? */
+ /* TODO(iter) Rewrite as dagger. */
+ HBUINT16 k {klass};
+ const RangeRecord *arr = rangeRecord.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
+ if (arr[i].value == k && arr[i].intersects (glyphs))
return true;
return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
index 2217d298fb..f523e35c00 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -566,6 +566,26 @@ struct AnchorMatrix
return_trace (true);
}
+ bool subset (hb_subset_context_t *c,
+ unsigned cols,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+
+ auto indexes =
+ + hb_range (rows * cols)
+ | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % cols); })
+ ;
+
+ out->serialize (c->serializer,
+ (unsigned) rows,
+ this,
+ c->plan->layout_variation_idx_map,
+ indexes);
+ return_trace (true);
+ }
+
bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
{
TRACE_SANITIZE (this);
@@ -755,7 +775,7 @@ struct SinglePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -870,7 +890,7 @@ struct SinglePosFormat2
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned sub_length = valueFormat.get_len ();
@@ -1129,7 +1149,7 @@ struct PairSet
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->len = 0;
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned len1 = valueFormats[0].get_len ();
@@ -1250,7 +1270,7 @@ struct PairPosFormat1
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1441,7 +1461,7 @@ struct PairPosFormat2
})
;
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -1728,7 +1748,7 @@ struct CursivePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1904,7 +1924,7 @@ struct MarkBasePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -2025,10 +2045,37 @@ typedef AnchorMatrix LigatureAttach; /* component-major--
* mark-minor--
* ordered by class--zero-based. */
-typedef OffsetListOf<LigatureAttach> LigatureArray;
- /* Array of LigatureAttach
- * tables ordered by
- * LigatureCoverage Index */
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : OffsetListOf<LigatureAttach>
+{
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ Iterator coverage,
+ unsigned class_count,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ for (const auto _ : + hb_zip (coverage, *this)
+ | hb_filter (glyphset, hb_first))
+ {
+ auto *matrix = out->serialize_append (c->serializer);
+ if (unlikely (!matrix)) return_trace (false);
+
+ matrix->serialize_subset (c,
+ _.second,
+ this,
+ class_count,
+ klass_mapping);
+ }
+ return_trace (this->len);
+ }
+};
struct MarkLigPosFormat1
{
@@ -2130,8 +2177,56 @@ struct MarkLigPosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ hb_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+ if (!klass_mapping.get_population ()) return_trace (false);
+ out->classCount = klass_mapping.get_population ();
+
+ auto mark_iter =
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ auto new_mark_coverage =
+ + mark_iter
+ | hb_map_retains_sorting (hb_first)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->markCoverage.serialize (c->serializer, out)
+ .serialize (c->serializer, new_mark_coverage))
+ return_trace (false);
+
+ out->markArray.serialize (c->serializer, out)
+ .serialize (c->serializer,
+ &klass_mapping,
+ c->plan->layout_variation_idx_map,
+ &(this+markArray),
+ + mark_iter
+ | hb_map (hb_second));
+
+ auto new_ligature_coverage =
+ + hb_iter (this + ligatureCoverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->ligatureCoverage.serialize (c->serializer, out)
+ .serialize (c->serializer, new_ligature_coverage))
+ return_trace (false);
+
+ out->ligatureArray.serialize_subset (c, ligatureArray, this,
+ hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
+
+ return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2164,6 +2259,7 @@ struct MarkLigPosFormat1
DEFINE_SIZE_STATIC (12);
};
+
struct MarkLigPos
{
template <typename context_t, typename ...Ts>
@@ -2288,7 +2384,7 @@ struct MarkMarkPosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
index 2f41d67819..5f10ecb7ee 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -356,7 +356,7 @@ struct Sequence
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset)) return_trace (false);
@@ -447,7 +447,7 @@ struct MultipleSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -582,7 +582,7 @@ struct AlternateSet
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -682,7 +682,7 @@ struct AlternateSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -840,7 +840,7 @@ struct Ligature
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
@@ -1058,7 +1058,7 @@ struct LigatureSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index cb95e6dcd5..36a95ead15 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -89,7 +89,7 @@ struct hb_closure_context_t :
bool is_lookup_done (unsigned int lookup_index)
{
- if (done_lookups->in_error ())
+ if (unlikely (done_lookups->in_error ()))
return true;
/* Have we visited this lookup with the current set of glyphs? */
@@ -146,7 +146,6 @@ struct hb_closure_lookups_context_t :
if (is_lookup_visited (lookup_index))
return;
- set_lookup_visited (lookup_index);
nesting_level_left--;
recurse_func (this, lookup_index);
nesting_level_left++;
@@ -163,10 +162,10 @@ struct hb_closure_lookups_context_t :
bool is_lookup_visited (unsigned lookup_index)
{
- if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+ if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
return true;
- if (visited_lookups->in_error ())
+ if (unlikely (visited_lookups->in_error ()))
return true;
return visited_lookups->has (lookup_index);
@@ -660,7 +659,7 @@ struct hb_ot_apply_context_t :
void replace_glyph (hb_codepoint_t glyph_index) const
{
_set_glyph_props (glyph_index);
- buffer->replace_glyph (glyph_index);
+ (void) buffer->replace_glyph (glyph_index);
}
void replace_glyph_inplace (hb_codepoint_t glyph_index) const
{
@@ -671,13 +670,13 @@ struct hb_ot_apply_context_t :
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess, true);
- buffer->replace_glyph (glyph_index);
+ (void) buffer->replace_glyph (glyph_index);
}
void output_glyph_for_component (hb_codepoint_t glyph_index,
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess, false, true);
- buffer->output_glyph (glyph_index);
+ (void) buffer->output_glyph (glyph_index);
}
};
@@ -1044,7 +1043,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
hb_min (this_comp, last_num_components);
_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
@@ -1188,7 +1187,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
/* Don't recurse to ourself at same position.
* Note that this test is too naive, it doesn't catch longer loops. */
- if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+ if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
continue;
if (unlikely (!buffer->move_to (match_positions[idx])))
@@ -1226,7 +1225,8 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
* mean that n match positions where removed, as there might
* have been marks and default-ignorables in the sequence. We
* should instead drop match positions between current-position
- * and current-position + n instead.
+ * and current-position + n instead. Though, am not sure which
+ * one is better. Both cases have valid uses. Sigh.
*
* It should be possible to construct tests for both of these cases.
*/
@@ -1272,7 +1272,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
match_positions[next] += delta;
}
- buffer->move_to (end);
+ (void) buffer->move_to (end);
return_trace (true);
}
@@ -1389,9 +1389,11 @@ struct Rule
lookup_context);
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
+ if (!intersects (c->glyphs, lookup_context)) return;
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
@@ -1521,14 +1523,13 @@ struct RuleSet
;
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
-
- return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -1647,9 +1648,16 @@ struct ContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const
{
- + hb_iter (ruleSet)
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ nullptr
+ };
+
+ + hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second)
| hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -1700,7 +1708,7 @@ struct ContextFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1791,10 +1799,24 @@ struct ContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!(this+coverage).intersects (c->glyphs))
+ return;
+
+ const ClassDef &class_def = this+classDef;
+
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ &class_def
+ };
+
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
- ;
+ | hb_enumerate
+ | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
+ { return class_def.intersects_class (c->glyphs, p.first); })
+ | hb_map (hb_second)
+ | hb_apply ([&] (const RuleSet & _)
+ { _.closure_lookups (c, lookup_context); });
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
@@ -1860,8 +1882,8 @@ struct ContextFormat2
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
bool ret = true;
int non_zero_index = 0, index = 0;
- for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _ : + hb_enumerate (ruleSet)
- | hb_filter (klass_map, hb_first))
+ for (const auto& _ : + hb_enumerate (ruleSet)
+ | hb_filter (klass_map, hb_first))
{
auto *o = out->ruleSet.serialize_append (c->serializer);
if (unlikely (!o))
@@ -1945,6 +1967,8 @@ struct ContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!intersects (c->glyphs))
+ return;
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
recurse_lookups (c, lookupCount, lookupRecord);
}
@@ -2010,6 +2034,7 @@ struct ContextFormat3
for (const OffsetTo<Coverage>& offset : coverages)
{
+ /* TODO(subset) This looks like should not be necessary to write this way. */
auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
if (unlikely (!o)) return_trace (false);
if (!o->serialize_subset (c, offset, this)) return_trace (false);
@@ -2238,9 +2263,11 @@ struct ChainRule
lookup_context);
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
+ if (!intersects (c->glyphs, lookup_context)) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
@@ -2296,11 +2323,7 @@ struct ChainRule
{
c->copy (len);
for (const auto g : it)
- {
- HBUINT16 gid;
- gid = g;
- c->copy (gid);
- }
+ c->copy ((HBUINT16) g);
}
ChainRule* copy (hb_serialize_context_t *c,
@@ -2328,12 +2351,19 @@ struct ChainRule
| hb_map (mapping));
const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
- HBUINT16 lookupCount;
- lookupCount = lookupRecord.len;
- if (!c->copy (lookupCount)) return_trace (nullptr);
- for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+ if (!lookupCount) return_trace (nullptr);
+
+ for (unsigned i = 0; i < lookupRecord.len; i++)
+ {
+ if (!lookup_map->has (lookupRecord[i].lookupListIndex))
+ {
+ (*lookupCount)--;
+ continue;
+ }
if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
+ }
return_trace (out);
}
@@ -2351,7 +2381,7 @@ struct ChainRule
if (!backtrack_map)
{
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
if (!hb_all (backtrack, glyphset) ||
!hb_all (input, glyphset) ||
!hb_all (lookahead, glyphset))
@@ -2424,14 +2454,14 @@ struct ChainRuleSet
;
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
- return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -2552,9 +2582,16 @@ struct ChainContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const
{
- + hb_iter (ruleSet)
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ {nullptr, nullptr, nullptr}
+ };
+
+ + hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -2604,7 +2641,7 @@ struct ChainContextFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -2701,9 +2738,28 @@ struct ChainContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!(this+coverage).intersects (c->glyphs))
+ return;
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ | hb_enumerate
+ | hb_filter([&] (unsigned klass)
+ { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const ChainRuleSet &_)
+ { _.closure_lookups (c, lookup_context); })
;
}
@@ -2779,24 +2835,23 @@ struct ChainContextFormat2
out->coverage.serialize_subset (c, coverage, this);
hb_map_t backtrack_klass_map;
- out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
- if (unlikely (!c->serializer->check_success (!backtrack_klass_map.in_error ())))
- return_trace (false);
-
- // subset inputClassDef based on glyphs survived in Coverage subsetting
hb_map_t input_klass_map;
- out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
- if (unlikely (!c->serializer->check_success (!input_klass_map.in_error ())))
- return_trace (false);
-
hb_map_t lookahead_klass_map;
+
+ out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
+ // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
+ out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
- if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ())))
+
+ if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
+ input_klass_map,
+ lookahead_klass_map)))
return_trace (false);
- unsigned non_zero_index = 0, index = 0;
+ int non_zero_index = -1, index = 0;
bool ret = true;
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ auto last_non_zero = c->serializer->snapshot ();
for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
| hb_filter (input_klass_map, hb_first)
| hb_map (hb_second))
@@ -2812,19 +2867,20 @@ struct ChainContextFormat2
&backtrack_klass_map,
&input_klass_map,
&lookahead_klass_map))
+ {
+ last_non_zero = c->serializer->snapshot ();
non_zero_index = index;
+ }
index++;
}
if (!ret) return_trace (ret);
- //prune empty trailing ruleSets
- --index;
- while (index > non_zero_index)
- {
- out->ruleSet.pop ();
- index--;
+ // prune empty trailing ruleSets
+ if (index > non_zero_index) {
+ c->serializer->revert (last_non_zero);
+ out->ruleSet.len = non_zero_index + 1;
}
return_trace (bool (out->ruleSet));
@@ -2908,6 +2964,9 @@ struct ChainContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!intersects (c->glyphs))
+ return;
+
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
@@ -2986,13 +3045,16 @@ struct ChainContextFormat3
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
- if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+ if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+ return_trace (false);
- + it
- | hb_apply (subset_offset_array (c, *out, base))
- ;
+ for (auto& offset : it) {
+ auto *o = out->serialize_append (c->serializer);
+ if (unlikely (!o) || !o->serialize_subset (c, offset, base))
+ return_trace (false);
+ }
- return_trace (out->len);
+ return_trace (true);
}
bool subset (hb_subset_context_t *c) const
@@ -3113,6 +3175,24 @@ struct ExtensionFormat1
extensionLookupType != T::SubTable::Extension);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ out->format = format;
+ out->extensionLookupType = extensionLookupType;
+
+ const auto& src_offset =
+ reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset);
+ auto& dest_offset =
+ reinterpret_cast<LOffsetTo<typename T::SubTable> &> (out->extensionOffset);
+
+ return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
+ }
+
protected:
HBUINT16 format; /* Format identifier. Set to 1. */
HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
@@ -3143,6 +3223,18 @@ struct Extension
}
}
+ // Specialization of dispatch for subset. dispatch() normally just
+ // dispatches to the sub table this points too, but for subset
+ // we need to run subset on this subtable too.
+ template <typename ...Ts>
+ typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.subset (c);
+ default: return c->default_return_value ();
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -3320,20 +3412,34 @@ struct GSUBGPOS
return_trace (true);
}
- void closure_features (const hb_map_t *lookup_indexes, /* IN */
- hb_set_t *feature_indexes /* OUT */) const
+ void prune_features (const hb_map_t *lookup_indices, /* IN */
+ hb_set_t *feature_indices /* IN/OUT */) const
{
- unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
- for (unsigned i = 0; i < feature_count; i++)
+#ifndef HB_NO_VAR
+ // This is the set of feature indices which have alternate versions defined
+ // if the FeatureVariation's table and the alternate version(s) intersect the
+ // set of lookup indices.
+ hb_set_t alternate_feature_indices;
+ if (version.to_int () >= 0x00010001u)
+ (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
+ if (unlikely (alternate_feature_indices.in_error())) {
+ feature_indices->successful = false;
+ return;
+ }
+#endif
+
+ for (unsigned i : feature_indices->iter())
{
const Feature& f = get_feature (i);
- if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
- feature_indexes->add (i);
- }
+
+ if (f.featureParams.is_null ()
+ && !f.intersects_lookup_indexes (lookup_indices)
#ifndef HB_NO_VAR
- if (version.to_int () >= 0x00010001u)
- (this+featureVars).closure_features (lookup_indexes, feature_indexes);
+ && !alternate_feature_indices.has (i)
#endif
+ )
+ feature_indices->del (i);
+ }
}
unsigned int get_size () const
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index f25f0f9e23..89df949b26 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -76,7 +76,7 @@
* Tests whether a face includes any kerning data in the 'kern' table.
* Does NOT test for kerning lookups in the GPOS table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
bool
@@ -92,7 +92,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
* Tests whether a face includes any state-machine kerning in the 'kern' table.
* Does NOT examine the GPOS table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
bool
@@ -112,7 +112,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
*
* Does NOT examine the GPOS table.
*
- * Return value: %true is data found, false otherwise
+ * Return value: %true is data found, %false otherwise
*
**/
bool
@@ -268,7 +268,7 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
*
* Tests whether a face has any glyph classes defined in its GDEF table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
hb_bool_t
@@ -322,7 +322,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
* @face: The #hb_face_t to work on
* @glyph: The #hb_codepoint_t code point to query
* @start_offset: offset of the first attachment point to retrieve
- * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
+ * @point_count: (inout) (optional): Input = the maximum number of attachment points to return;
* Output = the actual number of attachment points returned (may be zero)
* @point_array: (out) (array length=point_count): The array of attachment points found for the query
*
@@ -350,7 +350,7 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
* @direction: The #hb_direction_t text direction to use
* @glyph: The #hb_codepoint_t code point to query
* @start_offset: offset of the first caret position to retrieve
- * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
+ * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return;
* Output = the actual number of caret positions returned (may be zero)
* @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
*
@@ -410,9 +410,9 @@ get_gsubgpos_table (hb_face_t *face,
/**
* hb_ot_layout_table_get_script_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @start_offset: offset of the first script tag to retrieve
- * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
+ * @script_count: (inout) (optional): Input = the maximum number of script tags to return;
* Output = the actual number of script tags returned (may be zero)
* @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
*
@@ -437,14 +437,14 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
/**
* hb_ot_layout_table_find_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_tag: #hb_tag_t of the script tag requested
* @script_index: (out): The index of the requested script tag
*
* Fetches the index if a given script tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the script is found, false otherwise
+ * Return value: %true if the script is found, %false otherwise
*
**/
hb_bool_t
@@ -481,7 +481,7 @@ hb_ot_layout_table_find_script (hb_face_t *face,
/**
* hb_ot_layout_table_choose_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_tags: Array of #hb_tag_t script tags
* @script_index: (out): The index of the requested script tag
* @chosen_script: (out): #hb_tag_t of the script tag requested
@@ -504,11 +504,22 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
/**
* hb_ot_layout_table_select_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_count: Number of script tags in the array
* @script_tags: Array of #hb_tag_t script tags
- * @script_index: (out): The index of the requested script
- * @chosen_script: (out): #hb_tag_t of the requested script
+ * @script_index: (out) (optional): The index of the requested script
+ * @chosen_script: (out) (optional): #hb_tag_t of the requested script
+ *
+ * Selects an OpenType script for @table_tag from the @script_tags array.
+ *
+ * If the table does not have any of the requested scripts, then `DFLT`,
+ * `dflt`, and `latn` tags are tried in that order. If the table still does not
+ * have any of these scripts, @script_index and @chosen_script are set to
+ * #HB_OT_LAYOUT_NO_SCRIPT_INDEX.
+ *
+ * Return value:
+ * %true if one of the requested scripts is selected, %false if a fallback
+ * script is selected or if no scripts are selected.
*
* Since: 2.0.0
**/
@@ -566,9 +577,9 @@ hb_ot_layout_table_select_script (hb_face_t *face,
/**
* hb_ot_layout_table_get_feature_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output = the actual number of feature tags returned (may be zero)
* @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
*
@@ -591,14 +602,14 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
/**
* hb_ot_layout_table_find_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_tag: The #hb_tag_t og the requested feature tag
* @feature_index: (out): The index of the requested feature
*
* Fetches the index for a given feature tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
**/
bool
hb_ot_layout_table_find_feature (hb_face_t *face,
@@ -626,10 +637,10 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
/**
* hb_ot_layout_script_get_language_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @start_offset: offset of the first language tag to retrieve
- * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
+ * @language_count: (inout) (optional): Input = the maximum number of language tags to return;
* Output = the actual number of language tags returned (may be zero)
* @language_tags: (out) (array length=language_count): Array of language tags found in the table
*
@@ -655,7 +666,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
/**
* hb_ot_layout_script_find_language:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_tag: The #hb_tag_t of the requested language
* @language_index: The index of the requested language
@@ -663,7 +674,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
* Fetches the index of a given language tag in the specified face's GSUB table
* or GPOS table, underneath the specified script tag.
*
- * Return value: %true if the language tag is found, false otherwise
+ * Return value: %true if the language tag is found, %false otherwise
*
* Since: ??
* Deprecated: ??
@@ -688,7 +699,7 @@ hb_ot_layout_script_find_language (hb_face_t *face,
/**
* hb_ot_layout_script_select_language:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_count: The number of languages in the specified script
* @language_tags: The array of language tags
@@ -697,7 +708,7 @@ hb_ot_layout_script_find_language (hb_face_t *face,
* Fetches the index of a given language tag in the specified face's GSUB table
* or GPOS table, underneath the specified script index.
*
- * Return value: %true if the language tag is found, false otherwise
+ * Return value: %true if the language tag is found, %false otherwise
*
* Since: 2.0.0
**/
@@ -731,7 +742,7 @@ hb_ot_layout_script_select_language (hb_face_t *face,
/**
* hb_ot_layout_language_get_required_feature_index:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_index: (out): The index of the requested feature
@@ -739,7 +750,7 @@ hb_ot_layout_script_select_language (hb_face_t *face,
* Fetches the index of a requested feature in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
**/
hb_bool_t
@@ -761,7 +772,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
/**
* hb_ot_layout_language_get_required_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_index: (out): The index of the requested feature
@@ -770,7 +781,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
* Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
* Since: 0.9.30
**/
@@ -796,11 +807,11 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
/**
* hb_ot_layout_language_get_feature_indexes:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output: the actual number of feature tags returned (may be zero)
* @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
*
@@ -827,11 +838,11 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
/**
* hb_ot_layout_language_get_feature_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output = the actual number of feature tags returned (may be zero)
* @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
*
@@ -868,7 +879,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
/**
* hb_ot_layout_language_find_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_tag: #hb_tag_t of the feature tag requested
@@ -877,7 +888,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
* Fetches the index of a given feature tag in the specified face's GSUB table
* or GPOS table, underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
**/
hb_bool_t
@@ -910,10 +921,10 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
/**
* hb_ot_layout_feature_get_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_index: The index of the requested feature
* @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
* Output = the actual number of lookups returned (may be zero)
* @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
*
@@ -944,7 +955,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
/**
* hb_ot_layout_table_get_lookup_count:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
*
* Fetches the total number of lookups enumerated in the specified
* face's GSUB table or GPOS table.
@@ -1101,7 +1112,7 @@ script_collect_features (hb_collect_features_context_t *c,
/**
* hb_ot_layout_collect_features:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @scripts: The array of scripts to collect features for
* @languages: The array of languages to collect features for
* @features: The array of features to collect
@@ -1152,7 +1163,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
/**
* hb_ot_layout_collect_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @scripts: The array of scripts to collect lookups for
* @languages: The array of languages to collect lookups for
* @features: The array of features to collect lookups for
@@ -1191,7 +1202,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
/**
* hb_ot_layout_lookup_collect_glyphs:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @lookup_index: The index of the feature lookup to query
* @glyphs_before: (out): Array of glyphs preceding the substitution range
* @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
@@ -1243,7 +1254,7 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
/**
* hb_ot_layout_table_find_feature_variations:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @coords: The variation coordinates to query
* @num_coords: The number of variation coordinates
* @variations_index: (out): The array of feature variations found for the query
@@ -1268,11 +1279,11 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
/**
* hb_ot_layout_feature_with_variations_get_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_index: The index of the feature to query
* @variations_index: The index of the feature variation to query
* @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
* Output = the actual number of lookups returned (may be zero)
* @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
*
@@ -1310,7 +1321,7 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
*
* Tests whether the specified face includes any GSUB substitutions.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
hb_bool_t
@@ -1331,7 +1342,7 @@ hb_ot_layout_has_substitution (hb_face_t *face)
* Tests whether a specified lookup in the specified face would
* trigger a substitution on the given glyph sequence.
*
- * Return value: %true if a substitution would be triggered, false otherwise
+ * Return value: %true if a substitution would be triggered, %false otherwise
*
* Since: 0.9.7
**/
@@ -1488,7 +1499,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
* hb_ot_layout_has_positioning:
* @face: #hb_face_t to work upon
*
- * Return value: %true if the face has GPOS data, false otherwise
+ * Tests whether the specified face includes any GPOS positioning.
+ *
+ * Return value: %true if the face has GPOS data, %false otherwise
*
**/
hb_bool_t
@@ -1561,7 +1574,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
* For more information on this distinction, see the [`size` feature documentation](
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.10
**/
@@ -1610,22 +1623,22 @@ hb_ot_layout_get_size_params (hb_face_t *face,
* @face: #hb_face_t to work upon
* @table_tag: table tag to query, "GSUB" or "GPOS".
* @feature_index: index of feature to query.
- * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string
* for a user-interface label for this feature. (May be NULL.)
- * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string
* that an application can use for tooltip text for this
* feature. (May be NULL.)
- * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
+ * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text
* that illustrates the effect of this feature. (May be NULL.)
- * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
- * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
+ * @num_named_parameters: (out) (optional): Number of named parameters. (May be zero.)
+ * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify
* strings for user-interface labels for the feature
* parameters. (Must be zero if numParameters is zero.)
*
* Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
* "Character Variant" ('cvXX') features.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.0.0
**/
@@ -1685,7 +1698,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face,
* @table_tag: table tag to query, "GSUB" or "GPOS".
* @feature_index: index of feature to query.
* @start_offset: offset of the first character to retrieve
- * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
+ * @char_count: (inout) (optional): Input = the maximum number of characters to return;
* Output = the actual number of characters returned (may be zero)
* @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
* The Unicode codepoints of the characters for which this feature provides
@@ -1769,7 +1782,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
if (applied)
ret = true;
else
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
return ret;
}
@@ -1907,7 +1920,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
* @baseline_tag: a baseline tag
* @direction: text direction.
* @script_tag: script tag.
- * @language_tag: language tag.
+ * @language_tag: language tag, currently unused.
* @coord: (out): baseline value if found.
*
* Fetches a baseline value from the face.
@@ -1964,7 +1977,7 @@ struct hb_get_glyph_alternates_dispatch_t :
* @lookup_index: index of the feature lookup to query.
* @glyph: a glyph id.
* @start_offset: starting offset.
- * @alternate_count: (inout) (allow-none): Input = the maximum number of alternate glyphs to return;
+ * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return;
* Output = the actual number of alternate glyphs returned (may be zero).
* @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
* Alternate glyphs associated with the glyph id.
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h
index 545d5f7fc4..d47ba0fc92 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.h
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -38,10 +38,35 @@
HB_BEGIN_DECLS
+/**
+ * HB_OT_TAG_BASE:
+ *
+ * OpenType [Baseline Table](https://docs.microsoft.com/en-us/typography/opentype/spec/base).
+ */
#define HB_OT_TAG_BASE HB_TAG('B','A','S','E')
+/**
+ * HB_OT_TAG_GDEF:
+ *
+ * OpenType [Glyph Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef).
+ */
#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
+/**
+ * HB_OT_TAG_GSUB:
+ *
+ * OpenType [Glyph Substitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub).
+ */
#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
+/**
+ * HB_OT_TAG_GPOS:
+ *
+ * OpenType [Glyph Positioning Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos).
+ */
#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+/**
+ * HB_OT_TAG_JSTF:
+ *
+ * OpenType [Justification Table](https://docs.microsoft.com/en-us/typography/opentype/spec/jstf).
+ */
#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
@@ -49,18 +74,34 @@ HB_BEGIN_DECLS
* Script & Language tags.
*/
+/**
+ * HB_OT_TAG_DEFAULT_SCRIPT:
+ *
+ * OpenType script tag, `DFLT`, for features that are not script-specific.
+ *
+ */
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
+/**
+ * HB_OT_TAG_DEFAULT_LANGUAGE:
+ *
+ * OpenType language tag, `dflt`. Not a valid language tag, but some fonts
+ * mistakenly use it.
+ */
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
/**
* HB_OT_MAX_TAGS_PER_SCRIPT:
*
+ * Maximum number of OpenType tags that can correspond to a give #hb_script_t.
+ *
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_SCRIPT 3u
/**
* HB_OT_MAX_TAGS_PER_LANGUAGE:
*
+ * Maximum number of OpenType tags that can correspond to a give #hb_language_t.
+ *
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u
@@ -144,9 +185,29 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS feature query and enumeration interface
*/
+/**
+ * HB_OT_LAYOUT_NO_SCRIPT_INDEX:
+ *
+ * Special value for script index indicating unsupported script.
+ */
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_FEATURE_INDEX:
+ *
+ * Special value for feature index indicating unsupported feature.
+ */
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX:
+ *
+ * Special value for language index indicating default or unsupported language.
+ */
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_VARIATIONS_INDEX:
+ *
+ * Special value for variations index indicating unsupported variation.
+ */
#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int
@@ -433,7 +494,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
* In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
*
- * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ * Baseline tags from [Baseline Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags) registry.
*
* Since: 2.6.0
*/
@@ -446,6 +507,7 @@ typedef enum {
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'),
HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'),
+ /*< private >*/
_HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_layout_baseline_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh
index f3bb15581a..ac61bc70de 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh
@@ -315,12 +315,13 @@ _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
+static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info);
static inline bool
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
- !_hb_glyph_info_ligated (info);
+ !_hb_glyph_info_substituted (info);
}
static inline bool
_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
diff --git a/thirdparty/harfbuzz/src/hb-ot-math.cc b/thirdparty/harfbuzz/src/hb-ot-math.cc
index 9d8c6e735a..5781d25f2a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-math.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face has a `MATH` table.
*
- * Return value: true if the table is found, false otherwise
+ * Return value: %true if the table is found, %false otherwise
*
* Since: 1.3.3
**/
@@ -142,7 +142,7 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
*
* Tests whether the given glyph index is an extended shape in the face.
*
- * Return value: true if the glyph is an extended shape, false otherwise
+ * Return value: %true if the glyph is an extended shape, %false otherwise
*
* Since: 1.3.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-ot-math.h b/thirdparty/harfbuzz/src/hb-ot-math.h
index ad864a762d..d3ffa19d85 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math.h
+++ b/thirdparty/harfbuzz/src/hb-ot-math.h
@@ -24,7 +24,7 @@
* Igalia Author(s): Frédéric Wang
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -40,18 +40,89 @@ HB_BEGIN_DECLS
* MATH
*/
+/**
+ * HB_OT_TAG_MATH:
+ *
+ * OpenType [Mathematical Typesetting Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math).
+ *
+ * Since: 1.3.3
+ */
#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
-/* Use with hb_buffer_set_script() for math shaping. */
+/**
+ * HB_OT_MATH_SCRIPT:
+ *
+ * OpenType script tag for math shaping, for use with
+ * Use with hb_buffer_set_script().
+ *
+ * Since: 1.3.3
+ */
#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
/* Types */
/**
* hb_ot_math_constant_t:
+ * @HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: scriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: scriptScriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: delimitedSubFormulaMinHeight
+ * @HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: displayOperatorMinHeight
+ * @HB_OT_MATH_CONSTANT_MATH_LEADING: mathLeading
+ * @HB_OT_MATH_CONSTANT_AXIS_HEIGHT: axisHeight
+ * @HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: accentBaseHeight
+ * @HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: flattenedAccentBaseHeight
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: subscriptShiftDown
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: subscriptTopMax
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: subscriptBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: superscriptShiftUp
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: superscriptShiftUpCramped
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: superscriptBottomMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: superscriptBaselineDropMax
+ * @HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: subSuperscriptGapMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: superscriptBottomMaxWithSubscript
+ * @HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: spaceAfterScript
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: upperLimitGapMin
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: upperLimitBaselineRiseMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: lowerLimitGapMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: lowerLimitBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: stackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: stackTopDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: stackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: stackBottomDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_GAP_MIN: stackGapMin
+ * @HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: stackDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: stretchStackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: stretchStackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: stretchStackGapAboveMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: stretchStackGapBelowMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: fractionNumeratorShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: fractionNumeratorDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: fractionDenominatorShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: fractionDenominatorDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: fractionNumeratorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: fractionNumDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: fractionRuleThickness
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: fractionDenominatorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: fractionDenomDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: skewedFractionHorizontalGap
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: skewedFractionVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: overbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: overbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: overbarExtraAscender
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: underbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: underbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: underbarExtraDescender
+ * @HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: radicalVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: radicalDisplayStyleVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: radicalRuleThickness
+ * @HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: radicalExtraAscender
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: radicalKernBeforeDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: radicalKernAfterDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: radicalDegreeBottomRaisePercent
*
- * The 'MATH' table constants specified at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/math
+ * The 'MATH' table constants, refer to
+ * [OpenType documentation](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table)
+ * For more explanations.
*
* Since: 1.3.3
*/
@@ -116,6 +187,10 @@ typedef enum {
/**
* hb_ot_math_kern_t:
+ * @HB_OT_MATH_KERN_TOP_RIGHT: The top right corner of the glyph.
+ * @HB_OT_MATH_KERN_TOP_LEFT: The top left corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_RIGHT: The bottom right corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_LEFT: The bottom left corner of the glyph.
*
* The math kerning-table types defined for the four corners
* of a glyph.
@@ -145,6 +220,8 @@ typedef struct hb_ot_math_glyph_variant_t {
/**
* hb_ot_math_glyph_part_flags_t:
+ * @HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER: This is an extender glyph part that
+ * can be repeated to reach the desired length.
*
* Flags for math glyph parts.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-meta.cc b/thirdparty/harfbuzz/src/hb-ot-meta.cc
index 54a0e10f9b..35c8eb523f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-meta.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-meta.cc
@@ -41,9 +41,11 @@
* hb_ot_meta_get_entry_tags:
* @face: a face object
* @start_offset: iteration's start offset
- * @entries_count:(inout) (allow-none): buffer size as input, filled size as output
+ * @entries_count:(inout) (optional): buffer size as input, filled size as output
* @entries: (out caller-allocates) (array length=entries_count): entries tags buffer
*
+ * Fetches all available feature types.
+ *
* Return value: Number of all available feature types.
*
* Since: 2.6.0
diff --git a/thirdparty/harfbuzz/src/hb-ot-meta.h b/thirdparty/harfbuzz/src/hb-ot-meta.h
index 0278d84148..7748eb4958 100644
--- a/thirdparty/harfbuzz/src/hb-ot-meta.h
+++ b/thirdparty/harfbuzz/src/hb-ot-meta.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -54,6 +54,7 @@ typedef enum {
HB_OT_META_TAG_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'),
HB_OT_META_TAG_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g'),
+ /*< private >*/
_HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_meta_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.cc b/thirdparty/harfbuzz/src/hb-ot-metrics.cc
index 3065ea2adf..72aeff82d6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-metrics.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-metrics.cc
@@ -119,11 +119,11 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_position:
- * @font: a #hb_font_t object.
+ * @font: an #hb_font_t object.
* @metrics_tag: tag of metrics value you like to fetch.
* @position: (out) (optional): result of metrics value from the font.
*
- * It fetches metrics value corresponding to a given tag from a font.
+ * Fetches metrics value corresponding to @metrics_tag from @font.
*
* Returns: Whether found the requested metrics in the font.
* Since: 2.6.0
@@ -193,10 +193,13 @@ hb_ot_metrics_get_position (hb_font_t *font,
#ifndef HB_NO_VAR
/**
* hb_ot_metrics_get_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ *
+ * Fetches metrics value corresponding to @metrics_tag from @font with the
+ * current font variation settings applied.
*
- * Returns:
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
@@ -208,10 +211,13 @@ hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_x_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
*
- * Returns:
+ * Fetches horizontal metrics value corresponding to @metrics_tag from @font
+ * with the current font variation settings applied.
+ *
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
@@ -223,10 +229,13 @@ hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_y_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ *
+ * Fetches vertical metrics value corresponding to @metrics_tag from @font with
+ * the current font variation settings applied.
*
- * Returns:
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.h b/thirdparty/harfbuzz/src/hb-ot-metrics.h
index 42c7363c03..5841fc8b0f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-metrics.h
+++ b/thirdparty/harfbuzz/src/hb-ot-metrics.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -66,7 +66,8 @@ HB_BEGIN_DECLS
* @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size.
* @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset.
*
- * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags
+ * Metric tags corresponding to [MVAR Value
+ * Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags)
*
* Since: 2.6.0
**/
@@ -100,6 +101,7 @@ typedef enum {
HB_OT_METRICS_TAG_UNDERLINE_SIZE = HB_TAG ('u','n','d','s'),
HB_OT_METRICS_TAG_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o'),
+ /*< private >*/
_HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_metrics_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-name.cc b/thirdparty/harfbuzz/src/hb-ot-name.cc
index 10122b8c2e..4588226e6e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-name.cc
@@ -46,7 +46,7 @@
/**
* hb_ot_name_list_names:
* @face: font face.
- * @num_entries: (out) (allow-none): number of returned entries.
+ * @num_entries: (out) (optional): number of returned entries.
*
* Enumerates all available name IDs and language combinations. Returned
* array is owned by the @face and should not be modified. It can be
@@ -150,7 +150,7 @@ hb_ot_name_get_utf (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
@@ -177,7 +177,7 @@ hb_ot_name_get_utf8 (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
@@ -203,7 +203,7 @@ hb_ot_name_get_utf16 (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-name.h b/thirdparty/harfbuzz/src/hb-ot-name.h
index 6f3fcd2427..9359014c8a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name.h
+++ b/thirdparty/harfbuzz/src/hb-ot-name.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index 7d31b712c4..8e98f87f4e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -177,15 +177,14 @@ struct OS2
if (!c->plan->glyphs_requested->is_empty ())
{
hb_map_t unicode_glyphid_map;
-
+
OT::cmap::accelerator_t cmap;
cmap.init (c->plan->source);
cmap.collect_mapping (&unicodes, &unicode_glyphid_map);
cmap.fini ();
-
- if (c->plan->unicodes->is_empty ()) unicodes.clear ();
- else hb_set_set (&unicodes, c->plan->unicodes);
-
+
+ hb_set_set (&unicodes, c->plan->unicodes);
+
+ unicode_glyphid_map.iter ()
| hb_filter (c->plan->glyphs_requested, hb_second)
| hb_map (hb_first)
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index 8586331cd4..f22d6e244d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -87,7 +87,6 @@ struct post
if (unlikely (!post_prime)) return_trace (false);
serialize (c->serializer);
- if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
index b15e145f2f..41e3dd38ab 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -142,7 +142,7 @@
OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
- /* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+ /* static_assert_expr (len(FromGlyphs) == len(ToGlyphs)) */
#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
OT_SUBLOOKUP(Name, 1, \
@@ -151,7 +151,7 @@
OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
- /* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+ /* static_assert_expr (len(FirstGlyphs) == len(LigatureSetOffsets)) */
#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
index 1e93f0efd5..1f244f940c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -33,7 +33,7 @@
/* buffer var allocations */
-#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */
#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
index f5915f43ae..dbedd6af0c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
@@ -119,7 +119,7 @@ data_destroy_hangul (void *data)
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */
-#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */
static bool
is_zero_width_char (hb_font_t *font,
@@ -205,7 +205,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
- buffer->next_glyph ();
+ if (unlikely (!buffer->next_glyph ())) break;
if (!is_zero_width_char (font, u))
{
buffer->merge_out_clusters (start, end + 1);
@@ -218,23 +218,25 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
else
{
/* No valid syllable as base for tone mark; try to insert dotted circle. */
- if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
- font->has_glyph (0x25CCu))
+ if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
+ font->has_glyph (0x25CCu))
{
hb_codepoint_t chars[2];
- if (!is_zero_width_char (font, u)) {
+ if (!is_zero_width_char (font, u))
+ {
chars[0] = u;
chars[1] = 0x25CCu;
- } else {
+ } else
+ {
chars[0] = 0x25CCu;
chars[1] = u;
}
- buffer->replace_glyphs (1, 2, chars);
+ (void) buffer->replace_glyphs (1, 2, chars);
}
else
{
/* No dotted circle available in the font; just leave tone mark untouched. */
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
start = end = buffer->out_len;
@@ -271,9 +273,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
if (font->has_glyph (s))
{
- buffer->replace_glyphs (t ? 3 : 2, 1, &s);
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->replace_glyphs (t ? 3 : 2, 1, &s);
end = start + 1;
continue;
}
@@ -285,17 +285,19 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
* Set jamo features on the individual glyphs, and advance past them.
*/
buffer->cur().hangul_shaping_feature() = LJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
buffer->cur().hangul_shaping_feature() = VJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (t)
{
buffer->cur().hangul_shaping_feature() = TJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
end = start + 3;
}
else
end = start + 2;
+ if (unlikely (!buffer->successful))
+ break;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_out_clusters (start, end);
continue;
@@ -321,9 +323,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t new_s = s + new_tindex;
if (font->has_glyph (new_s))
{
- buffer->replace_glyphs (2, 1, &new_s);
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->replace_glyphs (2, 1, &new_s);
end = start + 1;
continue;
}
@@ -347,19 +347,18 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
(!tindex || font->has_glyph (decomposed[2])))
{
unsigned int s_len = tindex ? 3 : 2;
- buffer->replace_glyphs (1, s_len, decomposed);
+ (void) buffer->replace_glyphs (1, s_len, decomposed);
/* If we decomposed an LV because of a non-combining T following,
* we want to include this T in the syllable.
*/
if (has_glyph && !tindex)
{
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
s_len++;
}
-
if (unlikely (!buffer->successful))
- return;
+ break;
/* We decomposed S: apply jamo features to the individual glyphs
* that are now in buffer->out_info.
@@ -383,17 +382,15 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (has_glyph)
{
- /* We didn't decompose the S, so just advance past it. */
+ /* We didn't decompose the S, so just advance past it and fall through. */
end = start + 1;
- buffer->next_glyph ();
- continue;
}
}
/* Didn't find a recognizable syllable, so we leave end <= start;
* this will prevent tone-mark reordering happening.
*/
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
index 670b6bf486..74bf3ca0fa 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -31,8 +31,37 @@
#include "hb.hh"
+enum indic_syllable_type_t {
+ indic_consonant_syllable,
+ indic_vowel_syllable,
+ indic_standalone_cluster,
+ indic_symbol_cluster,
+ indic_broken_cluster,
+ indic_non_indic_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-indic-machine.hh"
+#line 45 "hb-ot-shape-complex-indic-machine.hh"
+#define indic_syllable_machine_ex_A 10u
+#define indic_syllable_machine_ex_C 1u
+#define indic_syllable_machine_ex_CM 17u
+#define indic_syllable_machine_ex_CS 19u
+#define indic_syllable_machine_ex_DOTTEDCIRCLE 12u
+#define indic_syllable_machine_ex_H 4u
+#define indic_syllable_machine_ex_M 7u
+#define indic_syllable_machine_ex_N 3u
+#define indic_syllable_machine_ex_PLACEHOLDER 11u
+#define indic_syllable_machine_ex_RS 13u
+#define indic_syllable_machine_ex_Ra 16u
+#define indic_syllable_machine_ex_Repha 15u
+#define indic_syllable_machine_ex_SM 8u
+#define indic_syllable_machine_ex_Symbol 18u
+#define indic_syllable_machine_ex_V 2u
+#define indic_syllable_machine_ex_ZWJ 6u
+#define indic_syllable_machine_ex_ZWNJ 5u
+
+
+#line 65 "hb-ot-shape-complex-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u,
@@ -384,18 +413,18 @@ static const int indic_syllable_machine_error = -1;
static const int indic_syllable_machine_en_main = 39;
-#line 36 "hb-ot-shape-complex-indic-machine.rl"
+#line 46 "hb-ot-shape-complex-indic-machine.rl"
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
+#line 102 "hb-ot-shape-complex-indic-machine.rl"
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -407,7 +436,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 411 "hb-ot-shape-complex-indic-machine.hh"
+#line 440 "hb-ot-shape-complex-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -415,7 +444,7 @@ find_syllables_indic (hb_buffer_t *buffer)
act = 0;
}
-#line 113 "hb-ot-shape-complex-indic-machine.rl"
+#line 122 "hb-ot-shape-complex-indic-machine.rl"
p = 0;
@@ -423,7 +452,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 427 "hb-ot-shape-complex-indic-machine.hh"
+#line 456 "hb-ot-shape-complex-indic-machine.hh"
{
int _slen;
int _trans;
@@ -437,7 +466,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 441 "hb-ot-shape-complex-indic-machine.hh"
+#line 470 "hb-ot-shape-complex-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -460,64 +489,64 @@ _eof_trans:
{te = p+1;}
break;
case 11:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
break;
case 13:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
break;
case 14:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
break;
case 17:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
break;
case 19:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
break;
case 15:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_broken_cluster); }}
break;
case 16:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
break;
case 1:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
break;
case 3:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
break;
case 7:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
break;
case 8:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
break;
case 4:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); }}
break;
case 6:
#line 1 "NONE"
{ switch( act ) {
case 1:
- {{p = ((te))-1;} found_syllable (consonant_syllable); }
+ {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
break;
case 5:
- {{p = ((te))-1;} found_syllable (broken_cluster); }
+ {{p = ((te))-1;} found_syllable (indic_broken_cluster); }
break;
case 6:
- {{p = ((te))-1;} found_syllable (non_indic_cluster); }
+ {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
break;
}
}
@@ -525,22 +554,22 @@ _eof_trans:
case 18:
#line 1 "NONE"
{te = p+1;}
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
{act = 1;}
break;
case 5:
#line 1 "NONE"
{te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
{act = 5;}
break;
case 12:
#line 1 "NONE"
{te = p+1;}
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
{act = 6;}
break;
-#line 544 "hb-ot-shape-complex-indic-machine.hh"
+#line 573 "hb-ot-shape-complex-indic-machine.hh"
}
_again:
@@ -549,7 +578,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 553 "hb-ot-shape-complex-indic-machine.hh"
+#line 582 "hb-ot-shape-complex-indic-machine.hh"
}
if ( ++p != pe )
@@ -565,7 +594,7 @@ _again:
}
-#line 121 "hb-ot-shape-complex-indic-machine.rl"
+#line 130 "hb-ot-shape-complex-indic-machine.rl"
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
index a150fd2486..dd204b23c1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
@@ -82,7 +82,7 @@
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
-static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
+static const uint16_t indic_table[] = {
#define indic_offset_0x0028u 0
@@ -404,7 +404,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
}; /* Table items: 1792; occupancy: 70% */
-INDIC_TABLE_ELEMENT_TYPE
+uint16_t
hb_indic_get_categories (hb_codepoint_t u)
{
switch (u >> 12)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
index 652ef47040..a4f2d9a847 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-indic.hh"
+#include "hb-ot-shape-complex-indic-machine.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
#include "hb-ot-layout.hh"
@@ -337,19 +338,6 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
return POS_BASE_C;
}
-
-enum indic_syllable_type_t {
- indic_consonant_syllable,
- indic_vowel_syllable,
- indic_standalone_cluster,
- indic_symbol_cluster,
- indic_broken_cluster,
- indic_non_indic_cluster,
-};
-
-#include "hb-ot-shape-complex-indic-machine.hh"
-
-
static void
setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -764,7 +752,28 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* We could use buffer->sort() for this, if there was no special
* reordering of pre-base stuff happening later...
* We don't want to merge_clusters all of that, which buffer->sort()
- * would.
+ * would. Here's a concrete example:
+ *
+ * Assume there's a pre-base consonant and explicit Halant before base,
+ * followed by a prebase-reordering (left) Matra:
+ *
+ * C,H,ZWNJ,B,M
+ *
+ * At this point in reordering we would have:
+ *
+ * M,C,H,ZWNJ,B
+ *
+ * whereas in final reordering we will bring the Matra closer to Base:
+ *
+ * C,H,ZWNJ,M,B
+ *
+ * That's why we don't want to merge-clusters anything before the Base
+ * at this point. But if something moved from after Base to before it,
+ * we should merge clusters from base to them. In final-reordering, we
+ * only move things around before base, and merge-clusters up to base.
+ * These two merge-clusters from the two sides of base will interlock
+ * to merge things correctly. See:
+ * https://github.com/harfbuzz/harfbuzz/issues/2272
*/
if (indic_plan->is_old_spec || end - start > 127)
buffer->merge_clusters (base, end);
@@ -774,17 +783,18 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
for (unsigned int i = base; i < end; i++)
if (info[i].syllable() != 255)
{
+ unsigned int min = i;
unsigned int max = i;
unsigned int j = start + info[i].syllable();
while (j != i)
{
+ min = hb_min (min, j);
max = hb_max (max, j);
unsigned int next = start + info[j].syllable();
info[j].syllable() = 255; /* So we don't process j later again. */
j = next;
}
- if (i != max)
- buffer->merge_clusters (i, max + 1);
+ buffer->merge_clusters (hb_max (base, min), max + 1);
}
}
@@ -938,69 +948,6 @@ initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
}
-static inline void
-insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == indic_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_indic_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().indic_category() == OT_Repha)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
@@ -1008,11 +955,16 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan,
{
if (!buffer->message (font, "start reordering indic initial"))
return;
+
update_consonant_positions_indic (plan, font, buffer);
- insert_dotted_circles_indic (plan, font, buffer);
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ indic_broken_cluster,
+ OT_DOTTEDCIRCLE,
+ OT_Repha);
foreach_syllable (buffer, start, end)
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
+
(void) buffer->message (font, "end reordering indic initial");
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
index 41bd8bd6cc..dcb28a4e84 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
@@ -29,16 +29,14 @@
#include "hb.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape-complex-syllabic.hh"
/* buffer var allocations */
-#define indic_category() complex_var_u8_0() /* indic_category_t */
-#define indic_position() complex_var_u8_1() /* indic_position_t */
+#define indic_category() complex_var_u8_category() /* indic_category_t */
+#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */
-#define INDIC_TABLE_ELEMENT_TYPE uint16_t
-
/* Cateories used in the OpenType spec:
* https://docs.microsoft.com/en-us/typography/script-development/devanagari
*/
@@ -177,7 +175,7 @@ enum indic_matra_category_t {
#define INDIC_COMBINE_CATEGORIES(S,M) \
( \
- ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+ static_assert_expr (S < 255 && M < 255) + \
( S | \
( \
( \
@@ -194,7 +192,7 @@ enum indic_matra_category_t {
) \
)
-HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+HB_INTERNAL uint16_t
hb_indic_get_categories (hb_codepoint_t u);
@@ -307,17 +305,12 @@ static const hb_codepoint_t ra_chars[] = {
0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
-
- 0x179Au, /* Khmer */
};
static inline bool
is_ra (hb_codepoint_t u)
{
- for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
- if (u == ra_chars[i])
- return true;
- return false;
+ return hb_array (ra_chars).lfind (u);
}
static inline void
@@ -325,7 +318,7 @@ set_indic_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_category_t cat = (indic_category_t) (type & 0xFFu);
indic_position_t pos = (indic_position_t) (type >> 8);
@@ -370,6 +363,7 @@ set_indic_properties (hb_glyph_info_t &info)
else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
+ else if (unlikely (u == 0x0B55u)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/2849 */
else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
index a040318d34..82ab186a41 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
@@ -1,211 +1,179 @@
-
#line 1 "hb-ot-shape-complex-khmer-machine.rl"
/*
- * Copyright © 2011,2012 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
+* Copyright © 2011,2012 Google, Inc.
+*
+* This is part of HarfBuzz, a text shaping library.
+*
+* Permission is hereby granted, without written agreement and without
+* license or royalty fees, to use, copy, modify, and distribute this
+* software and its documentation for any purpose, provided that the
+* above copyright notice and the following two paragraphs appear in
+* all copies of this software.
+*
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*
+* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*
+* Google Author(s): Behdad Esfahbod
+*/
#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#include "hb.hh"
+enum khmer_syllable_type_t {
+ khmer_consonant_syllable,
+ khmer_broken_cluster,
+ khmer_non_khmer_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-khmer-machine.hh"
+#line 41 "hb-ot-shape-complex-khmer-machine.hh"
+#define khmer_syllable_machine_ex_C 1u
+#define khmer_syllable_machine_ex_Coeng 14u
+#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
+#define khmer_syllable_machine_ex_PLACEHOLDER 11u
+#define khmer_syllable_machine_ex_Ra 16u
+#define khmer_syllable_machine_ex_Robatic 20u
+#define khmer_syllable_machine_ex_V 2u
+#define khmer_syllable_machine_ex_VAbv 26u
+#define khmer_syllable_machine_ex_VBlw 27u
+#define khmer_syllable_machine_ex_VPre 28u
+#define khmer_syllable_machine_ex_VPst 29u
+#define khmer_syllable_machine_ex_Xgroup 21u
+#define khmer_syllable_machine_ex_Ygroup 22u
+#define khmer_syllable_machine_ex_ZWJ 6u
+#define khmer_syllable_machine_ex_ZWNJ 5u
+
+
+#line 59 "hb-ot-shape-complex-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
- 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
- 5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u,
- 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u,
- 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u,
- 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u,
- 0
+ 2u, 8u, 2u, 6u, 2u, 8u, 2u, 6u,
+ 0u, 0u, 2u, 6u, 2u, 8u, 2u, 6u,
+ 2u, 8u, 2u, 6u, 2u, 6u, 2u, 8u,
+ 2u, 6u, 0u, 0u, 2u, 6u, 2u, 8u,
+ 2u, 6u, 2u, 8u, 2u, 6u, 2u, 8u,
+ 0u, 11u, 2u, 11u, 2u, 11u, 2u, 11u,
+ 7u, 7u, 2u, 7u, 2u, 11u, 2u, 11u,
+ 2u, 11u, 0u, 0u, 2u, 8u, 2u, 11u,
+ 2u, 11u, 7u, 7u, 2u, 7u, 2u, 11u,
+ 2u, 11u, 0u, 0u, 2u, 11u, 2u, 11u,
+ 0u
};
-static const char _khmer_syllable_machine_key_spans[] = {
- 22, 17, 22, 17, 16, 17, 22, 17,
- 22, 17, 17, 22, 17, 16, 17, 22,
- 17, 22, 17, 22, 29, 25, 25, 25,
- 1, 18, 25, 25, 25, 16, 22, 25,
- 25, 1, 18, 25, 25, 16, 25, 25
+static const signed char _khmer_syllable_machine_char_class[] = {
+ 0, 0, 1, 1, 2, 2, 1, 1,
+ 1, 1, 3, 3, 1, 4, 1, 0,
+ 1, 1, 1, 5, 6, 7, 1, 1,
+ 1, 8, 9, 10, 11, 0
};
static const short _khmer_syllable_machine_index_offsets[] = {
- 0, 23, 41, 64, 82, 99, 117, 140,
- 158, 181, 199, 217, 240, 258, 275, 293,
- 316, 334, 357, 375, 398, 428, 454, 480,
- 506, 508, 527, 553, 579, 605, 622, 645,
- 671, 697, 699, 718, 744, 770, 787, 813
+ 0, 7, 12, 19, 24, 25, 30, 37,
+ 42, 49, 54, 59, 66, 71, 72, 77,
+ 84, 89, 96, 101, 108, 120, 130, 140,
+ 150, 151, 157, 167, 177, 187, 188, 195,
+ 205, 215, 216, 222, 232, 242, 243, 253,
+ 0
};
-static const char _khmer_syllable_machine_indicies[] = {
- 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 2,
- 3, 0, 0, 0, 0, 4, 0, 1,
- 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 3,
- 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 3, 0, 0, 0, 0, 4, 0,
- 5, 5, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 0, 6, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 6, 0, 7, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 0, 9, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 10, 0, 0,
- 0, 0, 4, 0, 9, 9, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 10, 0, 11, 11,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 12, 0,
- 0, 0, 0, 4, 0, 11, 11, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 0, 14,
- 14, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 15,
- 13, 14, 14, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 15, 16, 16, 16, 16, 17, 16,
- 18, 18, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 17, 16, 19, 19, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 19, 16, 20, 20, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 21, 16, 22, 22, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 23, 16, 16,
- 16, 16, 17, 16, 22, 22, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 23, 16, 24, 24,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 25, 16,
- 16, 16, 16, 17, 16, 24, 24, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 25, 16, 14,
- 14, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 26, 15,
- 16, 16, 16, 16, 17, 16, 28, 28,
- 27, 27, 29, 29, 27, 27, 27, 27,
- 2, 2, 27, 30, 27, 28, 27, 27,
- 27, 27, 15, 19, 27, 27, 27, 17,
- 23, 25, 21, 27, 32, 32, 31, 31,
- 31, 31, 31, 31, 31, 33, 31, 31,
- 31, 31, 31, 2, 3, 6, 31, 31,
- 31, 4, 10, 12, 8, 31, 34, 34,
- 31, 31, 31, 31, 31, 31, 31, 35,
- 31, 31, 31, 31, 31, 31, 3, 6,
- 31, 31, 31, 4, 10, 12, 8, 31,
- 5, 5, 31, 31, 31, 31, 31, 31,
- 31, 35, 31, 31, 31, 31, 31, 31,
- 4, 6, 31, 31, 31, 31, 31, 31,
- 8, 31, 6, 31, 7, 7, 31, 31,
- 31, 31, 31, 31, 31, 35, 31, 31,
- 31, 31, 31, 31, 8, 6, 31, 36,
- 36, 31, 31, 31, 31, 31, 31, 31,
- 35, 31, 31, 31, 31, 31, 31, 10,
- 6, 31, 31, 31, 4, 31, 31, 8,
- 31, 37, 37, 31, 31, 31, 31, 31,
- 31, 31, 35, 31, 31, 31, 31, 31,
- 31, 12, 6, 31, 31, 31, 4, 10,
- 31, 8, 31, 34, 34, 31, 31, 31,
- 31, 31, 31, 31, 33, 31, 31, 31,
- 31, 31, 31, 3, 6, 31, 31, 31,
- 4, 10, 12, 8, 31, 28, 28, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 28, 31, 14, 14,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 15, 38,
- 38, 38, 38, 17, 38, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 41, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 18,
- 18, 39, 39, 39, 39, 39, 39, 39,
- 41, 39, 39, 39, 39, 39, 39, 17,
- 19, 39, 39, 39, 39, 39, 39, 21,
- 39, 19, 39, 20, 20, 39, 39, 39,
- 39, 39, 39, 39, 41, 39, 39, 39,
- 39, 39, 39, 21, 19, 39, 42, 42,
- 39, 39, 39, 39, 39, 39, 39, 41,
- 39, 39, 39, 39, 39, 39, 23, 19,
- 39, 39, 39, 17, 39, 39, 21, 39,
- 43, 43, 39, 39, 39, 39, 39, 39,
- 39, 41, 39, 39, 39, 39, 39, 39,
- 25, 19, 39, 39, 39, 17, 23, 39,
- 21, 39, 44, 44, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 44, 39, 45, 45, 39, 39, 39,
- 39, 39, 39, 39, 30, 39, 39, 39,
- 39, 39, 26, 15, 19, 39, 39, 39,
- 17, 23, 25, 21, 39, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 30, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 0
+static const signed char _khmer_syllable_machine_indicies[] = {
+ 1, 0, 0, 2, 3, 0, 4, 1,
+ 0, 0, 0, 3, 1, 0, 0, 0,
+ 3, 0, 4, 5, 0, 0, 0, 4,
+ 6, 7, 0, 0, 0, 8, 9, 0,
+ 0, 0, 10, 0, 4, 9, 0, 0,
+ 0, 10, 11, 0, 0, 0, 12, 0,
+ 4, 11, 0, 0, 0, 12, 14, 13,
+ 13, 13, 15, 14, 16, 16, 16, 15,
+ 16, 17, 18, 16, 16, 16, 17, 19,
+ 20, 16, 16, 16, 21, 22, 16, 16,
+ 16, 23, 16, 17, 22, 16, 16, 16,
+ 23, 24, 16, 16, 16, 25, 16, 17,
+ 24, 16, 16, 16, 25, 14, 16, 16,
+ 26, 15, 16, 17, 29, 28, 30, 2,
+ 31, 28, 15, 19, 17, 23, 25, 21,
+ 33, 32, 34, 2, 3, 6, 4, 10,
+ 12, 8, 35, 32, 36, 32, 3, 6,
+ 4, 10, 12, 8, 5, 32, 36, 32,
+ 4, 6, 32, 32, 32, 8, 6, 7,
+ 32, 36, 32, 8, 6, 37, 32, 36,
+ 32, 10, 6, 4, 32, 32, 8, 38,
+ 32, 36, 32, 12, 6, 4, 10, 32,
+ 8, 35, 32, 34, 32, 3, 6, 4,
+ 10, 12, 8, 29, 14, 39, 39, 39,
+ 15, 39, 17, 41, 40, 42, 40, 15,
+ 19, 17, 23, 25, 21, 18, 40, 42,
+ 40, 17, 19, 40, 40, 40, 21, 19,
+ 20, 40, 42, 40, 21, 19, 43, 40,
+ 42, 40, 23, 19, 17, 40, 40, 21,
+ 44, 40, 42, 40, 25, 19, 17, 23,
+ 40, 21, 45, 46, 40, 31, 26, 15,
+ 19, 17, 23, 25, 21, 41, 40, 31,
+ 40, 15, 19, 17, 23, 25, 21, 0
};
-static const char _khmer_syllable_machine_trans_targs[] = {
- 20, 1, 28, 22, 23, 3, 24, 5,
- 25, 7, 26, 9, 27, 20, 10, 31,
- 20, 32, 12, 33, 14, 34, 16, 35,
- 18, 36, 39, 20, 21, 30, 37, 20,
- 0, 29, 2, 4, 6, 8, 20, 20,
- 11, 13, 15, 17, 38, 19
+static const signed char _khmer_syllable_machine_index_defaults[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 13, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 28, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 39, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40,
+ 0
};
-static const char _khmer_syllable_machine_trans_actions[] = {
- 1, 0, 2, 2, 2, 0, 0, 0,
- 2, 0, 2, 0, 2, 3, 0, 4,
- 5, 2, 0, 0, 0, 2, 0, 2,
- 0, 2, 4, 8, 2, 9, 0, 10,
- 0, 0, 0, 0, 0, 0, 11, 12,
- 0, 0, 0, 0, 4, 0
+static const signed char _khmer_syllable_machine_cond_targs[] = {
+ 20, 1, 28, 22, 23, 3, 24, 5,
+ 25, 7, 26, 9, 27, 20, 10, 31,
+ 20, 32, 12, 33, 14, 34, 16, 35,
+ 18, 36, 39, 20, 20, 21, 30, 37,
+ 20, 0, 29, 2, 4, 6, 8, 20,
+ 20, 11, 13, 15, 17, 38, 19, 0
};
-static const char _khmer_syllable_machine_to_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+static const signed char _khmer_syllable_machine_cond_actions[] = {
+ 1, 0, 2, 2, 2, 0, 0, 0,
+ 2, 0, 2, 0, 2, 3, 0, 4,
+ 5, 2, 0, 0, 0, 2, 0, 2,
+ 0, 2, 4, 0, 8, 2, 9, 0,
+ 10, 0, 0, 0, 0, 0, 0, 11,
+ 12, 0, 0, 0, 0, 4, 0, 0
};
-static const char _khmer_syllable_machine_from_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+static const signed char _khmer_syllable_machine_to_state_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
};
-static const unsigned char _khmer_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 14, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 0, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 39, 40,
- 40, 40, 40, 40, 40, 40, 40, 40
+static const signed char _khmer_syllable_machine_from_state_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
+static const signed char _khmer_syllable_machine_eof_trans[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 14, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 28, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 40, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 0
};
static const int khmer_syllable_machine_start = 20;
@@ -215,156 +183,271 @@ static const int khmer_syllable_machine_error = -1;
static const int khmer_syllable_machine_en_main = 20;
-#line 36 "hb-ot-shape-complex-khmer-machine.rl"
+#line 43 "hb-ot-shape-complex-khmer-machine.rl"
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+#line 86 "hb-ot-shape-complex-khmer-machine.rl"
#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
+HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
static void
find_syllables_khmer (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 242 "hb-ot-shape-complex-khmer-machine.hh"
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+#line 210 "hb-ot-shape-complex-khmer-machine.hh"
{
- cs = khmer_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
+ cs = (int)khmer_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
}
-
-#line 100 "hb-ot-shape-complex-khmer-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
-
-#line 258 "hb-ot-shape-complex-khmer-machine.hh"
+
+#line 106 "hb-ot-shape-complex-khmer-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 226 "hb-ot-shape-complex-khmer-machine.hh"
{
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
- case 7:
+ unsigned int _trans = 0;
+ const unsigned char * _keys;
+ const signed char * _inds;
+ int _ic;
+ _resume: {}
+ if ( p == pe && p != eof )
+ goto _out;
+ switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
+ case 7: {
+ {
#line 1 "NONE"
- {ts = p;}
- break;
-#line 272 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
- _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
-
- _slen = _khmer_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
- ( info[p].khmer_category()) <= _keys[1] ?
- ( info[p].khmer_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _khmer_syllable_machine_trans_targs[_trans];
-
- if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
- case 2:
+ {ts = p;}}
+
+#line 241 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ if ( p == eof ) {
+ if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = (unsigned int)_khmer_syllable_machine_eof_trans[cs] - 1;
+ }
+ }
+ else {
+ _keys = ( _khmer_syllable_machine_trans_keys + ((cs<<1)));
+ _inds = ( _khmer_syllable_machine_indicies + (_khmer_syllable_machine_index_offsets[cs]));
+
+ if ( (info[p].khmer_category()) <= 29 && (info[p].khmer_category()) >= 1 ) {
+ _ic = (int)_khmer_syllable_machine_char_class[(int)(info[p].khmer_category()) - 1];
+ if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
+ _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
+ else
+ _trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
+ }
+ else {
+ _trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
+ }
+
+ }
+ cs = (int)_khmer_syllable_machine_cond_targs[_trans];
+
+ if ( _khmer_syllable_machine_cond_actions[_trans] != 0 ) {
+
+ switch ( _khmer_syllable_machine_cond_actions[_trans] ) {
+ case 2: {
+ {
#line 1 "NONE"
- {te = p+1;}
- break;
- case 8:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p+1;{ found_syllable (non_khmer_cluster); }}
- break;
- case 10:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
- break;
- case 12:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
- break;
- case 11:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (non_khmer_cluster); }}
- break;
- case 1:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
- break;
- case 5:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
- break;
- case 3:
+ {te = p+1;}}
+
+#line 279 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 8: {
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p+1;{
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ }}
+
+#line 292 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 10: {
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_consonant_syllable); }
+ }}
+
+#line 305 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 12: {
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ }}
+
+#line 318 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 11: {
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ }}
+
+#line 331 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 1: {
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ {p = ((te))-1;
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_consonant_syllable); }
+ }}
+
+#line 345 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 5: {
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {p = ((te))-1;
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ }}
+
+#line 359 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 3: {
+ {
#line 1 "NONE"
- { switch( act ) {
- case 2:
- {{p = ((te))-1;} found_syllable (broken_cluster); }
- break;
- case 3:
- {{p = ((te))-1;} found_syllable (non_khmer_cluster); }
- break;
- }
- }
- break;
- case 4:
+ {switch( act ) {
+ case 2: {
+ p = ((te))-1;
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ break;
+ }
+ case 3: {
+ p = ((te))-1;
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ break;
+ }
+ }}
+ }
+
+#line 385 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 4: {
+ {
#line 1 "NONE"
- {te = p+1;}
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 2;}
- break;
- case 9:
+ {te = p+1;}}
+
+#line 395 "hb-ot-shape-complex-khmer-machine.hh"
+
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 2;}}
+
+#line 401 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 9: {
+ {
#line 1 "NONE"
- {te = p+1;}
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 3;}
- break;
-#line 342 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
-_again:
- switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
- case 6:
+ {te = p+1;}}
+
+#line 411 "hb-ot-shape-complex-khmer-machine.hh"
+
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 3;}}
+
+#line 417 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ }
+
+ if ( p == eof ) {
+ if ( cs >= 20 )
+ goto _out;
+ }
+ else {
+ switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+ case 6: {
+ {
#line 1 "NONE"
- {ts = 0;}
- break;
-#line 351 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
+ {ts = 0;}}
+
+#line 437 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ p += 1;
+ goto _resume;
+ }
+ _out: {}
}
-
- }
-
-#line 108 "hb-ot-shape-complex-khmer-machine.rl"
-
+
+#line 114 "hb-ot-shape-complex-khmer-machine.rl"
+
}
#undef found_syllable
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl
deleted file mode 100644
index e7f14533dd..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright © 2011,2012 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-
-#include "hb.hh"
-
-%%{
- machine khmer_syllable_machine;
- alphtype unsigned char;
- write data;
-}%%
-
-%%{
-
-# Same order as enum khmer_category_t. Not sure how to avoid duplication.
-C = 1;
-V = 2;
-ZWNJ = 5;
-ZWJ = 6;
-PLACEHOLDER = 11;
-DOTTEDCIRCLE = 12;
-Coeng= 14;
-Ra = 16;
-Robatic = 20;
-Xgroup = 21;
-Ygroup = 22;
-VAbv = 26;
-VBlw = 27;
-VPre = 28;
-VPst = 29;
-
-c = (C | Ra | V);
-cn = c.((ZWJ|ZWNJ)?.Robatic)?;
-joiner = (ZWJ | ZWNJ);
-xgroup = (joiner*.Xgroup)*;
-ygroup = Ygroup*;
-
-# This grammar was experimentally extracted from what Uniscribe allows.
-
-matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?;
-syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup;
-
-
-broken_cluster = (Coeng.cn)* (Coeng | syllable_tail);
-consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
-other = any;
-
-main := |*
- consonant_syllable => { found_syllable (consonant_syllable); };
- broken_cluster => { found_syllable (broken_cluster); };
- other => { found_syllable (non_khmer_cluster); };
-*|;
-
-
-}%%
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-static void
-find_syllables_khmer (hb_buffer_t *buffer)
-{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
- %%{
- write init;
- getkey info[p].khmer_category();
- }%%
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
- %%{
- write exec;
- }%%
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
index d6fcd7c814..dddba142a3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-khmer.hh"
+#include "hb-ot-shape-complex-khmer-machine.hh"
#include "hb-ot-layout.hh"
@@ -140,27 +141,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan)
struct khmer_shape_plan_t
{
- bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
- {
- hb_codepoint_t glyph = virama_glyph;
- if (unlikely (virama_glyph == (hb_codepoint_t) -1))
- {
- if (!font->get_nominal_glyph (0x17D2u, &glyph))
- glyph = 0;
- /* Technically speaking, the spec says we should apply 'locl' to virama too.
- * Maybe one day... */
-
- /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
- * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */
- virama_glyph = glyph;
- }
-
- *pglyph = glyph;
- return glyph != 0;
- }
-
- mutable hb_codepoint_t virama_glyph;
-
hb_mask_t mask_array[KHMER_NUM_FEATURES];
};
@@ -171,8 +151,6 @@ data_create_khmer (const hb_ot_shape_plan_t *plan)
if (unlikely (!khmer_plan))
return nullptr;
- khmer_plan->virama_glyph = (hb_codepoint_t) -1;
-
for (unsigned int i = 0; i < ARRAY_LENGTH (khmer_plan->mask_array); i++)
khmer_plan->mask_array[i] = (khmer_features[i].flags & F_GLOBAL) ?
0 : plan->map.get_1_mask (khmer_features[i].tag);
@@ -186,15 +164,6 @@ data_destroy_khmer (void *data)
free (data);
}
-
-enum khmer_syllable_type_t {
- khmer_consonant_syllable,
- khmer_broken_cluster,
- khmer_non_khmer_cluster,
-};
-
-#include "hb-ot-shape-complex-khmer-machine.hh"
-
static void
setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -321,76 +290,17 @@ reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
}
}
-static inline void
-insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == khmer_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_khmer_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().khmer_category() == OT_Repha)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering khmer")) {
- insert_dotted_circles_khmer (plan, font, buffer);
+ if (buffer->message (font, "start reordering khmer"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ khmer_broken_cluster,
+ OT_DOTTEDCIRCLE,
+ OT_Repha);
foreach_syllable (buffer, start, end)
reorder_syllable_khmer (plan, font->face, buffer, start, end);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
index 11a77bfd4b..e24d68a8b5 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
@@ -54,7 +54,7 @@ set_khmer_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- khmer_category_t cat = (khmer_category_t) (type & 0x7Fu);
+ khmer_category_t cat = (khmer_category_t) (type & 0xFFu);
indic_position_t pos = (indic_position_t) (type >> 8);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh
deleted file mode 100644
index 9ec1f3eb7c..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright © 2019,2020 David Corbett
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH
-#define HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH
-
-#include "hb.hh"
-
-
-template <typename Iter>
-struct machine_index_t :
- hb_iter_with_fallback_t<machine_index_t<Iter>,
- typename Iter::item_t>
-{
- machine_index_t (const Iter& it) : it (it) {}
- machine_index_t (const machine_index_t& o) : it (o.it) {}
-
- static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
- static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
-
- typename Iter::item_t __item__ () const { return *it; }
- typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
- unsigned __len__ () const { return it.len (); }
- void __next__ () { ++it; }
- void __forward__ (unsigned n) { it += n; }
- void __prev__ () { --it; }
- void __rewind__ (unsigned n) { it -= n; }
- void operator = (unsigned n)
- { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
- void operator = (const machine_index_t& o) { *this = (*o.it).first; }
- bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
- bool operator != (const machine_index_t& o) const { return !(*this == o); }
-
- private:
- Iter it;
-};
-struct
-{
- template <typename Iter,
- hb_requires (hb_is_iterable (Iter))>
- machine_index_t<hb_iter_type<Iter>>
- operator () (Iter&& it) const
- { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
-}
-HB_FUNCOBJ (machine_index);
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
index c2f4c0045c..c09497896d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -31,8 +31,43 @@
#include "hb.hh"
+enum myanmar_syllable_type_t {
+ myanmar_consonant_syllable,
+ myanmar_punctuation_cluster,
+ myanmar_broken_cluster,
+ myanmar_non_myanmar_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 43 "hb-ot-shape-complex-myanmar-machine.hh"
+#define myanmar_syllable_machine_ex_A 10u
+#define myanmar_syllable_machine_ex_As 18u
+#define myanmar_syllable_machine_ex_C 1u
+#define myanmar_syllable_machine_ex_CS 19u
+#define myanmar_syllable_machine_ex_D 32u
+#define myanmar_syllable_machine_ex_D0 20u
+#define myanmar_syllable_machine_ex_DB 3u
+#define myanmar_syllable_machine_ex_GB 11u
+#define myanmar_syllable_machine_ex_H 4u
+#define myanmar_syllable_machine_ex_IV 2u
+#define myanmar_syllable_machine_ex_MH 21u
+#define myanmar_syllable_machine_ex_MR 22u
+#define myanmar_syllable_machine_ex_MW 23u
+#define myanmar_syllable_machine_ex_MY 24u
+#define myanmar_syllable_machine_ex_P 31u
+#define myanmar_syllable_machine_ex_PT 25u
+#define myanmar_syllable_machine_ex_Ra 16u
+#define myanmar_syllable_machine_ex_V 8u
+#define myanmar_syllable_machine_ex_VAbv 26u
+#define myanmar_syllable_machine_ex_VBlw 27u
+#define myanmar_syllable_machine_ex_VPre 28u
+#define myanmar_syllable_machine_ex_VPst 29u
+#define myanmar_syllable_machine_ex_VS 30u
+#define myanmar_syllable_machine_ex_ZWJ 6u
+#define myanmar_syllable_machine_ex_ZWNJ 5u
+
+
+#line 71 "hb-ot-shape-complex-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
@@ -293,18 +328,18 @@ static const int myanmar_syllable_machine_error = -1;
static const int myanmar_syllable_machine_en_main = 0;
-#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 44 "hb-ot-shape-complex-myanmar-machine.rl"
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 101 "hb-ot-shape-complex-myanmar-machine.rl"
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -316,7 +351,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 355 "hb-ot-shape-complex-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -324,7 +359,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
act = 0;
}
-#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 121 "hb-ot-shape-complex-myanmar-machine.rl"
p = 0;
@@ -332,7 +367,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 371 "hb-ot-shape-complex-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -346,7 +381,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 385 "hb-ot-shape-complex-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -365,38 +400,38 @@ _eof_trans:
switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
case 6:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 4:
-#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 10:
-#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (punctuation_cluster); }}
+#line 95 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_punctuation_cluster); }}
break;
case 8:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (broken_cluster); }}
+#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_broken_cluster); }}
break;
case 3:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 5:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 7:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
+#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_broken_cluster); }}
break;
case 9:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (non_myanmar_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
-#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 435 "hb-ot-shape-complex-myanmar-machine.hh"
}
_again:
@@ -405,7 +440,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 444 "hb-ot-shape-complex-myanmar-machine.hh"
}
if ( ++p != pe )
@@ -421,7 +456,7 @@ _again:
}
-#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 129 "hb-ot-shape-complex-myanmar-machine.rl"
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
index fe096ef28a..bc5dcb904c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-myanmar.hh"
+#include "hb-ot-shape-complex-myanmar-machine.hh"
/*
@@ -97,17 +98,6 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
}
-
-enum myanmar_syllable_type_t {
- myanmar_consonant_syllable,
- myanmar_punctuation_cluster,
- myanmar_broken_cluster,
- myanmar_non_myanmar_cluster,
-};
-
-#include "hb-ot-shape-complex-myanmar-machine.hh"
-
-
static void
setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -265,70 +255,16 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
}
-static inline void
-insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_myanmar_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering myanmar")) {
- insert_dotted_circles_myanmar (plan, font, buffer);
+ if (buffer->message (font, "start reordering myanmar"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ myanmar_broken_cluster,
+ OT_GB);
foreach_syllable (buffer, start, end)
reorder_syllable_myanmar (plan, font->face, buffer, start, end);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
index 7b9821e6ba..a6d68aae57 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
@@ -64,7 +64,7 @@ set_myanmar_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- unsigned int cat = type & 0x7Fu;
+ unsigned int cat = type & 0xFFu;
indic_position_t pos = (indic_position_t) (type >> 8);
/* Myanmar
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc
new file mode 100644
index 0000000000..46509abee2
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2021 Behdad Esfahbod.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#include "hb-ot-shape-complex-syllabic.hh"
+
+
+void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int broken_syllable_type,
+ unsigned int dottedcircle_category,
+ int repha_category)
+{
+ if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+ return;
+
+ /* Note: This loop is extra overhead, but should not be measurable.
+ * TODO Use a buffer scratch flag to remove the loop. */
+ bool has_broken_syllables = false;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if ((info[i].syllable() & 0x0F) == broken_syllable_type)
+ {
+ has_broken_syllables = true;
+ break;
+ }
+ if (likely (!has_broken_syllables))
+ return;
+
+
+ hb_codepoint_t dottedcircle_glyph;
+ if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ dottedcircle.complex_var_u8_category() = dottedcircle_category;
+ dottedcircle.codepoint = dottedcircle_glyph;
+
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+ while (buffer->idx < buffer->len && buffer->successful)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ if (unlikely (last_syllable != syllable && (syllable & 0x0F) == broken_syllable_type))
+ {
+ last_syllable = syllable;
+
+ hb_glyph_info_t ginfo = dottedcircle;
+ ginfo.cluster = buffer->cur().cluster;
+ ginfo.mask = buffer->cur().mask;
+ ginfo.syllable() = buffer->cur().syllable();
+
+ /* Insert dottedcircle after possible Repha. */
+ if (repha_category != -1)
+ {
+ while (buffer->idx < buffer->len && buffer->successful &&
+ last_syllable == buffer->cur().syllable() &&
+ buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
+ (void) buffer->next_glyph ();
+ }
+
+ (void) buffer->output_info (ginfo);
+ }
+ else
+ (void) buffer->next_glyph ();
+ }
+ buffer->swap_buffers ();
+}
+
+
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh
new file mode 100644
index 0000000000..c80b8fee1d
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2021 Behdad Esfahbod.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shape-complex.hh"
+
+
+HB_INTERNAL void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int broken_syllable_type,
+ unsigned int dottedcircle_category,
+ int repha_category = -1);
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
index 347ea2e7ac..4c3068173b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -323,20 +323,19 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
unsigned int count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+ for (buffer->idx = 0; buffer->idx < count /* No need for: && buffer->successful */;)
{
hb_codepoint_t u = buffer->cur().codepoint;
- if (likely (!IS_SARA_AM (u))) {
- buffer->next_glyph ();
+ if (likely (!IS_SARA_AM (u)))
+ {
+ if (unlikely (!buffer->next_glyph ())) break;
continue;
}
/* Is SARA AM. Decompose and reorder. */
- hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
- _hb_glyph_info_set_continuation (&nikhahit);
- buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u));
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
+ _hb_glyph_info_set_continuation (&buffer->prev());
+ if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
/* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
unsigned int end = buffer->out_len;
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
index 144e7d3a40..b4b2b75100 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
@@ -1,300 +1,348 @@
-
#line 1 "hb-ot-shape-complex-use-machine.rl"
/*
- * Copyright © 2015 Mozilla Foundation.
- * Copyright © 2015 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
+* Copyright © 2015 Mozilla Foundation.
+* Copyright © 2015 Google, Inc.
+*
+* This is part of HarfBuzz, a text shaping library.
+*
+* Permission is hereby granted, without written agreement and without
+* license or royalty fees, to use, copy, modify, and distribute this
+* software and its documentation for any purpose, provided that the
+* above copyright notice and the following two paragraphs appear in
+* all copies of this software.
+*
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*
+* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*
+* Mozilla Author(s): Jonathan Kew
+* Google Author(s): Behdad Esfahbod
+*/
#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#include "hb.hh"
-#include "hb-ot-shape-complex-machine-index.hh"
+#include "hb-ot-shape-complex-syllabic.hh"
+
+/* buffer var allocations */
+#define use_category() complex_var_u8_category()
+
+#define USE(Cat) use_syllable_machine_ex_##Cat
+
+enum use_syllable_type_t {
+ use_independent_cluster,
+ use_virama_terminated_cluster,
+ use_sakot_terminated_cluster,
+ use_standard_cluster,
+ use_number_joiner_terminated_cluster,
+ use_numeral_cluster,
+ use_symbol_cluster,
+ use_hieroglyph_cluster,
+ use_broken_cluster,
+ use_non_cluster,
+};
-#line 39 "hb-ot-shape-complex-use-machine.hh"
+
+#line 57 "hb-ot-shape-complex-use-machine.hh"
+#define use_syllable_machine_ex_B 1u
+#define use_syllable_machine_ex_CMAbv 31u
+#define use_syllable_machine_ex_CMBlw 32u
+#define use_syllable_machine_ex_CS 43u
+#define use_syllable_machine_ex_FAbv 24u
+#define use_syllable_machine_ex_FBlw 25u
+#define use_syllable_machine_ex_FMAbv 45u
+#define use_syllable_machine_ex_FMBlw 46u
+#define use_syllable_machine_ex_FMPst 47u
+#define use_syllable_machine_ex_FPst 26u
+#define use_syllable_machine_ex_G 49u
+#define use_syllable_machine_ex_GB 5u
+#define use_syllable_machine_ex_H 12u
+#define use_syllable_machine_ex_HN 13u
+#define use_syllable_machine_ex_HVM 44u
+#define use_syllable_machine_ex_J 50u
+#define use_syllable_machine_ex_MAbv 27u
+#define use_syllable_machine_ex_MBlw 28u
+#define use_syllable_machine_ex_MPre 30u
+#define use_syllable_machine_ex_MPst 29u
+#define use_syllable_machine_ex_N 4u
+#define use_syllable_machine_ex_O 0u
+#define use_syllable_machine_ex_R 18u
+#define use_syllable_machine_ex_S 19u
+#define use_syllable_machine_ex_SB 51u
+#define use_syllable_machine_ex_SE 52u
+#define use_syllable_machine_ex_SMAbv 41u
+#define use_syllable_machine_ex_SMBlw 42u
+#define use_syllable_machine_ex_SUB 11u
+#define use_syllable_machine_ex_Sk 48u
+#define use_syllable_machine_ex_VAbv 33u
+#define use_syllable_machine_ex_VBlw 34u
+#define use_syllable_machine_ex_VMAbv 37u
+#define use_syllable_machine_ex_VMBlw 38u
+#define use_syllable_machine_ex_VMPre 23u
+#define use_syllable_machine_ex_VMPst 39u
+#define use_syllable_machine_ex_VPre 22u
+#define use_syllable_machine_ex_VPst 35u
+#define use_syllable_machine_ex_ZWNJ 14u
+
+
+#line 99 "hb-ot-shape-complex-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 1u, 1u, 1u, 1u, 0u, 51u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 23u, 48u,
- 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u,
- 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u,
- 11u, 48u, 1u, 48u, 13u, 13u, 4u, 4u, 11u, 48u, 41u, 42u, 42u, 42u, 11u, 48u,
- 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u,
- 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u,
- 22u, 48u, 11u, 48u, 1u, 48u, 1u, 1u, 4u, 4u, 13u, 13u, 1u, 48u, 11u, 48u,
- 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, 0
+ 1u, 1u, 1u, 1u, 0u, 37u, 5u, 34u,
+ 5u, 34u, 1u, 1u, 10u, 34u, 11u, 34u,
+ 12u, 33u, 13u, 33u, 14u, 33u, 31u, 32u,
+ 32u, 32u, 12u, 34u, 12u, 34u, 12u, 34u,
+ 1u, 1u, 12u, 34u, 11u, 34u, 11u, 34u,
+ 11u, 34u, 10u, 34u, 10u, 34u, 10u, 34u,
+ 5u, 34u, 1u, 34u, 7u, 7u, 3u, 3u,
+ 5u, 34u, 27u, 28u, 28u, 28u, 5u, 34u,
+ 10u, 34u, 11u, 34u, 12u, 33u, 13u, 33u,
+ 14u, 33u, 31u, 32u, 32u, 32u, 12u, 34u,
+ 12u, 34u, 12u, 34u, 12u, 34u, 11u, 34u,
+ 11u, 34u, 11u, 34u, 10u, 34u, 10u, 34u,
+ 10u, 34u, 5u, 34u, 1u, 34u, 1u, 1u,
+ 3u, 3u, 7u, 7u, 1u, 34u, 5u, 34u,
+ 27u, 28u, 28u, 28u, 1u, 4u, 36u, 38u,
+ 35u, 38u, 35u, 37u, 0u
};
-static const char _use_syllable_machine_key_spans[] = {
- 1, 1, 52, 38, 38, 1, 27, 26,
- 24, 23, 22, 2, 1, 25, 25, 25,
- 1, 25, 26, 26, 26, 27, 27, 27,
- 38, 48, 1, 1, 38, 2, 1, 38,
- 27, 26, 24, 23, 22, 2, 1, 25,
- 25, 25, 25, 26, 26, 26, 27, 27,
- 27, 38, 48, 1, 1, 1, 48, 38,
- 2, 1, 5, 3, 4, 3
+static const signed char _use_syllable_machine_char_class[] = {
+ 0, 1, 2, 2, 3, 4, 2, 2,
+ 2, 2, 2, 5, 6, 7, 2, 2,
+ 2, 2, 8, 9, 2, 2, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 2, 24, 25, 26,
+ 2, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 2, 4, 57, 96, 135, 137, 165,
- 192, 217, 241, 264, 267, 269, 295, 321,
- 347, 349, 375, 402, 429, 456, 484, 512,
- 540, 579, 628, 630, 632, 671, 674, 676,
- 715, 743, 770, 795, 819, 842, 845, 847,
- 873, 899, 925, 951, 978, 1005, 1032, 1060,
- 1088, 1116, 1155, 1204, 1206, 1208, 1210, 1259,
- 1298, 1301, 1303, 1309, 1313, 1318
+ 0, 1, 2, 40, 70, 100, 101, 126,
+ 150, 172, 193, 213, 215, 216, 239, 262,
+ 285, 286, 309, 333, 357, 381, 406, 431,
+ 456, 486, 520, 521, 522, 552, 554, 555,
+ 585, 610, 634, 656, 677, 697, 699, 700,
+ 723, 746, 769, 792, 816, 840, 864, 889,
+ 914, 939, 969, 1003, 1004, 1005, 1006, 1040,
+ 1070, 1072, 1073, 1077, 1080, 1084, 0
+};
+
+static const signed char _use_syllable_machine_indicies[] = {
+ 1, 2, 4, 5, 6, 7, 8, 1,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 13, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 9, 36, 6, 37,
+ 39, 40, 38, 38, 38, 41, 42, 43,
+ 44, 45, 46, 47, 41, 48, 5, 49,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 56, 57, 58, 59, 40, 39, 40,
+ 38, 38, 38, 41, 42, 43, 44, 45,
+ 46, 47, 41, 48, 49, 49, 50, 51,
+ 52, 53, 54, 55, 38, 38, 38, 56,
+ 57, 58, 59, 40, 39, 41, 42, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 42, 57, 58, 59, 61, 42, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 53, 54, 55, 38, 38,
+ 38, 38, 57, 58, 59, 61, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 57, 58, 59, 44, 45, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 57, 58,
+ 59, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 57, 58, 59, 57, 58, 58,
+ 43, 44, 45, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 53, 54, 55, 38,
+ 38, 38, 38, 57, 58, 59, 61, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 54, 55, 38, 38,
+ 38, 38, 57, 58, 59, 61, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 55, 38, 38, 38,
+ 38, 57, 58, 59, 61, 63, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 50,
+ 51, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 51, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 41, 42, 43,
+ 44, 45, 38, 47, 41, 38, 38, 38,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 42, 57, 58, 59, 61, 41, 42,
+ 43, 44, 45, 38, 38, 41, 38, 38,
+ 38, 50, 51, 52, 53, 54, 55, 38,
+ 38, 38, 42, 57, 58, 59, 61, 41,
+ 42, 43, 44, 45, 46, 47, 41, 38,
+ 38, 38, 50, 51, 52, 53, 54, 55,
+ 38, 38, 38, 42, 57, 58, 59, 61,
+ 39, 40, 38, 38, 38, 41, 42, 43,
+ 44, 45, 46, 47, 41, 48, 38, 49,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 56, 57, 58, 59, 40, 39, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60,
+ 42, 43, 44, 45, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 53, 54, 55,
+ 60, 60, 60, 60, 57, 58, 59, 61,
+ 65, 7, 39, 40, 38, 38, 38, 41,
+ 42, 43, 44, 45, 46, 47, 41, 48,
+ 5, 49, 50, 51, 52, 53, 54, 55,
+ 12, 67, 38, 56, 57, 58, 59, 40,
+ 12, 67, 67, 1, 70, 69, 69, 69,
+ 13, 14, 15, 16, 17, 18, 19, 13,
+ 20, 22, 22, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 32, 33, 34, 35,
+ 70, 13, 14, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 23, 24, 25, 26,
+ 27, 28, 69, 69, 69, 14, 33, 34,
+ 35, 71, 14, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 26,
+ 27, 28, 69, 69, 69, 69, 33, 34,
+ 35, 71, 15, 16, 17, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 33, 34, 35,
+ 16, 17, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 33, 34, 35, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 33, 34,
+ 35, 33, 34, 34, 15, 16, 17, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 26, 27, 28, 69, 69, 69, 69, 33,
+ 34, 35, 71, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 27, 28, 69, 69, 69, 69, 33, 34,
+ 35, 71, 15, 16, 17, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 28, 69, 69, 69, 69, 33, 34, 35,
+ 71, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 23, 24, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 24, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 69, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 13, 14, 15, 16, 17, 69, 19, 13,
+ 69, 69, 69, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 14, 33, 34, 35,
+ 71, 13, 14, 15, 16, 17, 69, 69,
+ 13, 69, 69, 69, 23, 24, 25, 26,
+ 27, 28, 69, 69, 69, 14, 33, 34,
+ 35, 71, 13, 14, 15, 16, 17, 18,
+ 19, 13, 69, 69, 69, 23, 24, 25,
+ 26, 27, 28, 69, 69, 69, 14, 33,
+ 34, 35, 71, 1, 70, 69, 69, 69,
+ 13, 14, 15, 16, 17, 18, 19, 13,
+ 20, 69, 22, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 32, 33, 34, 35,
+ 70, 1, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 14, 15, 16, 17, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 26, 27, 28, 69, 69, 69, 69, 33,
+ 34, 35, 71, 1, 73, 10, 5, 69,
+ 69, 5, 1, 70, 10, 69, 69, 13,
+ 14, 15, 16, 17, 18, 19, 13, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 69, 32, 33, 34, 35, 70,
+ 1, 70, 69, 69, 69, 13, 14, 15,
+ 16, 17, 18, 19, 13, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 69, 69,
+ 69, 32, 33, 34, 35, 70, 29, 30,
+ 30, 5, 72, 72, 5, 75, 74, 36,
+ 36, 75, 74, 75, 36, 74, 37, 0
};
-static const char _use_syllable_machine_indicies[] = {
- 1, 0, 2, 0, 3, 4, 5, 5,
- 6, 7, 5, 5, 5, 5, 5, 1,
- 8, 9, 5, 5, 5, 5, 10, 11,
- 5, 5, 12, 13, 14, 15, 16, 17,
- 18, 12, 19, 20, 21, 22, 23, 24,
- 5, 25, 26, 27, 5, 28, 29, 30,
- 31, 32, 33, 34, 8, 35, 5, 36,
- 5, 38, 39, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 40, 41, 42, 43,
- 44, 45, 46, 40, 47, 4, 48, 49,
- 50, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 55, 56, 57, 58, 39, 37,
- 38, 39, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 40, 41, 42, 43, 44,
- 45, 46, 40, 47, 48, 48, 49, 50,
- 51, 37, 52, 53, 54, 37, 37, 37,
- 37, 55, 56, 57, 58, 39, 37, 38,
- 59, 40, 41, 42, 43, 44, 37, 37,
- 37, 37, 37, 37, 49, 50, 51, 37,
- 52, 53, 54, 37, 37, 37, 37, 41,
- 56, 57, 58, 60, 37, 41, 42, 43,
- 44, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 52, 53, 54, 37, 37,
- 37, 37, 37, 56, 57, 58, 60, 37,
- 42, 43, 44, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 56, 57, 58,
- 37, 43, 44, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 56, 57, 58,
- 37, 44, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 56, 57, 58, 37,
- 56, 57, 37, 57, 37, 42, 43, 44,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 52, 53, 54, 37, 37, 37,
- 37, 37, 56, 57, 58, 60, 37, 42,
- 43, 44, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 53, 54, 37,
- 37, 37, 37, 37, 56, 57, 58, 60,
- 37, 42, 43, 44, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 54, 37, 37, 37, 37, 37, 56, 57,
- 58, 60, 37, 62, 61, 42, 43, 44,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 56, 57, 58, 60, 37, 41,
- 42, 43, 44, 37, 37, 37, 37, 37,
- 37, 49, 50, 51, 37, 52, 53, 54,
- 37, 37, 37, 37, 41, 56, 57, 58,
- 60, 37, 41, 42, 43, 44, 37, 37,
- 37, 37, 37, 37, 37, 50, 51, 37,
- 52, 53, 54, 37, 37, 37, 37, 41,
- 56, 57, 58, 60, 37, 41, 42, 43,
- 44, 37, 37, 37, 37, 37, 37, 37,
- 37, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 41, 56, 57, 58, 60, 37,
- 40, 41, 42, 43, 44, 37, 46, 40,
- 37, 37, 37, 49, 50, 51, 37, 52,
- 53, 54, 37, 37, 37, 37, 41, 56,
- 57, 58, 60, 37, 40, 41, 42, 43,
- 44, 37, 37, 40, 37, 37, 37, 49,
- 50, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 41, 56, 57, 58, 60, 37,
- 40, 41, 42, 43, 44, 45, 46, 40,
- 37, 37, 37, 49, 50, 51, 37, 52,
- 53, 54, 37, 37, 37, 37, 41, 56,
- 57, 58, 60, 37, 38, 39, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 40,
- 41, 42, 43, 44, 45, 46, 40, 47,
- 37, 48, 49, 50, 51, 37, 52, 53,
- 54, 37, 37, 37, 37, 55, 56, 57,
- 58, 39, 37, 38, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 41, 42, 43, 44, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 52,
- 53, 54, 59, 59, 59, 59, 59, 56,
- 57, 58, 60, 59, 64, 63, 6, 65,
- 38, 39, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 40, 41, 42, 43, 44,
- 45, 46, 40, 47, 4, 48, 49, 50,
- 51, 37, 52, 53, 54, 37, 11, 66,
- 37, 55, 56, 57, 58, 39, 37, 11,
- 66, 67, 66, 67, 1, 69, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 21, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 68, 68, 68, 31, 32, 33,
- 34, 69, 68, 12, 13, 14, 15, 16,
- 68, 68, 68, 68, 68, 68, 22, 23,
- 24, 68, 25, 26, 27, 68, 68, 68,
- 68, 13, 32, 33, 34, 70, 68, 13,
- 14, 15, 16, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 25, 26, 27,
- 68, 68, 68, 68, 68, 32, 33, 34,
- 70, 68, 14, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 32,
- 33, 34, 68, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 32,
- 33, 34, 68, 16, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 32, 33,
- 34, 68, 32, 33, 68, 33, 68, 14,
- 15, 16, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 25, 26, 27, 68,
- 68, 68, 68, 68, 32, 33, 34, 70,
- 68, 14, 15, 16, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 26,
- 27, 68, 68, 68, 68, 68, 32, 33,
- 34, 70, 68, 14, 15, 16, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 27, 68, 68, 68, 68, 68,
- 32, 33, 34, 70, 68, 14, 15, 16,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 32, 33, 34, 70, 68, 13,
- 14, 15, 16, 68, 68, 68, 68, 68,
- 68, 22, 23, 24, 68, 25, 26, 27,
- 68, 68, 68, 68, 13, 32, 33, 34,
- 70, 68, 13, 14, 15, 16, 68, 68,
- 68, 68, 68, 68, 68, 23, 24, 68,
- 25, 26, 27, 68, 68, 68, 68, 13,
- 32, 33, 34, 70, 68, 13, 14, 15,
- 16, 68, 68, 68, 68, 68, 68, 68,
- 68, 24, 68, 25, 26, 27, 68, 68,
- 68, 68, 13, 32, 33, 34, 70, 68,
- 12, 13, 14, 15, 16, 68, 18, 12,
- 68, 68, 68, 22, 23, 24, 68, 25,
- 26, 27, 68, 68, 68, 68, 13, 32,
- 33, 34, 70, 68, 12, 13, 14, 15,
- 16, 68, 68, 12, 68, 68, 68, 22,
- 23, 24, 68, 25, 26, 27, 68, 68,
- 68, 68, 13, 32, 33, 34, 70, 68,
- 12, 13, 14, 15, 16, 17, 18, 12,
- 68, 68, 68, 22, 23, 24, 68, 25,
- 26, 27, 68, 68, 68, 68, 13, 32,
- 33, 34, 70, 68, 1, 69, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 68, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 68, 68, 68, 31, 32, 33,
- 34, 69, 68, 1, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 13, 14, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 25,
- 26, 27, 68, 68, 68, 68, 68, 32,
- 33, 34, 70, 68, 1, 71, 72, 68,
- 9, 68, 4, 68, 68, 68, 4, 68,
- 68, 68, 68, 68, 1, 69, 9, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 20, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 28, 29, 68, 31, 32, 33,
- 34, 69, 68, 1, 69, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 12, 13,
- 14, 15, 16, 17, 18, 12, 19, 20,
- 21, 22, 23, 24, 68, 25, 26, 27,
- 68, 68, 68, 68, 31, 32, 33, 34,
- 69, 68, 28, 29, 68, 29, 68, 4,
- 71, 71, 71, 4, 71, 74, 73, 35,
- 73, 35, 74, 73, 74, 73, 35, 73,
- 36, 73, 0
+static const signed char _use_syllable_machine_index_defaults[] = {
+ 0, 0, 6, 38, 38, 60, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 62, 38, 38, 38, 38, 38, 38, 38,
+ 38, 60, 64, 66, 38, 68, 68, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 72, 69, 69, 69, 69,
+ 69, 69, 72, 74, 74, 74, 0
};
-static const char _use_syllable_machine_trans_targs[] = {
- 2, 31, 42, 2, 3, 2, 26, 28,
- 51, 52, 54, 29, 32, 33, 34, 35,
- 36, 46, 47, 48, 55, 49, 43, 44,
- 45, 39, 40, 41, 56, 57, 58, 50,
- 37, 38, 2, 59, 61, 2, 4, 5,
- 6, 7, 8, 9, 10, 21, 22, 23,
- 24, 18, 19, 20, 13, 14, 15, 25,
- 11, 12, 2, 2, 16, 2, 17, 2,
- 27, 2, 30, 2, 2, 0, 1, 2,
- 53, 2, 60
+static const signed char _use_syllable_machine_cond_targs[] = {
+ 2, 31, 42, 2, 2, 3, 2, 26,
+ 28, 51, 52, 54, 29, 32, 33, 34,
+ 35, 36, 46, 47, 48, 55, 49, 43,
+ 44, 45, 39, 40, 41, 56, 57, 58,
+ 50, 37, 38, 2, 59, 61, 2, 4,
+ 5, 6, 7, 8, 9, 10, 21, 22,
+ 23, 24, 18, 19, 20, 13, 14, 15,
+ 25, 11, 12, 2, 2, 16, 2, 17,
+ 2, 27, 2, 30, 2, 2, 0, 1,
+ 2, 53, 2, 60, 0
};
-static const char _use_syllable_machine_trans_actions[] = {
- 1, 2, 2, 5, 0, 6, 0, 0,
- 0, 0, 2, 0, 2, 2, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 0, 0, 0, 2,
- 0, 0, 7, 0, 0, 8, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 9, 10, 0, 11, 0, 12,
- 0, 13, 0, 14, 15, 0, 0, 16,
- 0, 17, 0
+static const signed char _use_syllable_machine_cond_actions[] = {
+ 1, 2, 2, 0, 5, 0, 6, 0,
+ 0, 0, 0, 2, 0, 2, 2, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 0, 0, 0,
+ 2, 0, 0, 7, 0, 0, 8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 10, 0, 11, 0,
+ 12, 0, 13, 0, 14, 15, 0, 0,
+ 16, 0, 17, 0, 0
};
-static const char _use_syllable_machine_to_state_actions[] = {
- 0, 0, 3, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0
+static const signed char _use_syllable_machine_to_state_actions[] = {
+ 0, 0, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
};
-static const char _use_syllable_machine_from_state_actions[] = {
- 0, 0, 4, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0
+static const signed char _use_syllable_machine_from_state_actions[] = {
+ 0, 0, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
};
-static const short _use_syllable_machine_eof_trans[] = {
- 1, 1, 0, 38, 38, 60, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 62, 38, 38, 38, 38, 38, 38, 38,
- 38, 60, 64, 66, 38, 68, 68, 69,
- 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 72, 69, 69, 69, 69,
- 69, 69, 72, 74, 74, 74
+static const signed char _use_syllable_machine_eof_trans[] = {
+ 1, 1, 4, 39, 39, 61, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39,
+ 63, 39, 39, 39, 39, 39, 39, 39,
+ 39, 61, 65, 67, 39, 69, 69, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 73, 70, 70, 70, 70,
+ 70, 70, 73, 75, 75, 75, 0
};
static const int use_syllable_machine_start = 2;
@@ -304,185 +352,376 @@ static const int use_syllable_machine_error = -1;
static const int use_syllable_machine_en_main = 2;
-#line 39 "hb-ot-shape-complex-use-machine.rl"
+#line 59 "hb-ot-shape-complex-use-machine.rl"
-#line 154 "hb-ot-shape-complex-use-machine.rl"
+#line 176 "hb-ot-shape-complex-use-machine.rl"
#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
- for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
- info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
+HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
+ for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+
+template <typename Iter>
+struct machine_index_t :
+hb_iter_with_fallback_t<machine_index_t<Iter>,
+typename Iter::item_t>
+{
+ machine_index_t (const Iter& it) : it (it) {}
+ machine_index_t (const machine_index_t& o) : it (o.it) {}
+
+ static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+ static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+
+ typename Iter::item_t __item__ () const { return *it; }
+ typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
+ unsigned __len__ () const { return it.len (); }
+ void __next__ () { ++it; }
+ void __forward__ (unsigned n) { it += n; }
+ void __prev__ () { --it; }
+ void __rewind__ (unsigned n) { it -= n; }
+ void operator = (unsigned n)
+ { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
+ void operator = (const machine_index_t& o) { *this = (*o.it).first; }
+ bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
+ bool operator != (const machine_index_t& o) const { return !(*this == o); }
+
+ private:
+ Iter it;
+};
+struct
+{
+ template <typename Iter,
+ hb_requires (hb_is_iterable (Iter))>
+ machine_index_t<hb_iter_type<Iter>>
+ operator () (Iter&& it) const
+ { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
+}
+HB_FUNCOBJ (machine_index);
+
+
static bool
not_standard_default_ignorable (const hb_glyph_info_t &i)
-{ return !(i.use_category() == USE_O && _hb_glyph_info_is_default_ignorable (&i)); }
+{ return !(i.use_category() == USE(O) && _hb_glyph_info_is_default_ignorable (&i)); }
-static void
+static inline void
find_syllables_use (hb_buffer_t *buffer)
{
- hb_glyph_info_t *info = buffer->info;
- auto p =
- + hb_iter (info, buffer->len)
- | hb_enumerate
- | hb_filter ([] (const hb_glyph_info_t &i) { return not_standard_default_ignorable (i); },
- hb_second)
- | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
- {
- if (p.second.use_category() == USE_ZWNJ)
- for (unsigned i = p.first + 1; i < buffer->len; ++i)
- if (not_standard_default_ignorable (info[i]))
- return !_hb_glyph_info_is_unicode_mark (&info[i]);
- return true;
- })
- | hb_enumerate
- | machine_index
- ;
- auto pe = p + p.len ();
- auto eof = +pe;
- auto ts = +p;
- auto te = +p;
- unsigned int act HB_UNUSED;
- int cs;
-
-#line 355 "hb-ot-shape-complex-use-machine.hh"
+ hb_glyph_info_t *info = buffer->info;
+ auto p =
+ + hb_iter (info, buffer->len)
+ | hb_enumerate
+ | hb_filter ([] (const hb_glyph_info_t &i) { return not_standard_default_ignorable (i); },
+ hb_second)
+ | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
+ {
+ if (p.second.use_category() == USE(ZWNJ))
+ for (unsigned i = p.first + 1; i < buffer->len; ++i)
+ if (not_standard_default_ignorable (info[i]))
+ return !_hb_glyph_info_is_unicode_mark (&info[i]);
+ return true;
+ })
+ | hb_enumerate
+ | machine_index
+ ;
+ auto pe = p + p.len ();
+ auto eof = +pe;
+ auto ts = +p;
+ auto te = +p;
+ unsigned int act HB_UNUSED;
+ int cs;
+
+#line 443 "hb-ot-shape-complex-use-machine.hh"
{
- cs = use_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
+ cs = (int)use_syllable_machine_start;
+ ts = 0;
+ te = 0;
}
-
-#line 198 "hb-ot-shape-complex-use-machine.rl"
-
-
- unsigned int syllable_serial = 1;
-
-#line 368 "hb-ot-shape-complex-use-machine.hh"
+
+#line 260 "hb-ot-shape-complex-use-machine.rl"
+
+
+ unsigned int syllable_serial = 1;
+
+#line 455 "hb-ot-shape-complex-use-machine.hh"
{
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _use_syllable_machine_from_state_actions[cs] ) {
- case 4:
+ unsigned int _trans = 0;
+ const unsigned char * _keys;
+ const signed char * _inds;
+ int _ic;
+ _resume: {}
+ if ( p == pe && p != eof )
+ goto _out;
+ switch ( _use_syllable_machine_from_state_actions[cs] ) {
+ case 4: {
+ {
#line 1 "NONE"
- {ts = p;}
- break;
-#line 382 "hb-ot-shape-complex-use-machine.hh"
- }
-
- _keys = _use_syllable_machine_trans_keys + (cs<<1);
- _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
-
- _slen = _use_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
- ( (*p).second.second.use_category()) <= _keys[1] ?
- ( (*p).second.second.use_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _use_syllable_machine_trans_targs[_trans];
-
- if ( _use_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _use_syllable_machine_trans_actions[_trans] ) {
- case 2:
+ {ts = p;}}
+
+#line 470 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ if ( p == eof ) {
+ if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = (unsigned int)_use_syllable_machine_eof_trans[cs] - 1;
+ }
+ }
+ else {
+ _keys = ( _use_syllable_machine_trans_keys + ((cs<<1)));
+ _inds = ( _use_syllable_machine_indicies + (_use_syllable_machine_index_offsets[cs]));
+
+ if ( ((*p).second.second.use_category()) <= 52 ) {
+ _ic = (int)_use_syllable_machine_char_class[(int)((*p).second.second.use_category()) - 0];
+ if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
+ _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
+ else
+ _trans = (unsigned int)_use_syllable_machine_index_defaults[cs];
+ }
+ else {
+ _trans = (unsigned int)_use_syllable_machine_index_defaults[cs];
+ }
+
+ }
+ cs = (int)_use_syllable_machine_cond_targs[_trans];
+
+ if ( _use_syllable_machine_cond_actions[_trans] != 0 ) {
+
+ switch ( _use_syllable_machine_cond_actions[_trans] ) {
+ case 2: {
+ {
#line 1 "NONE"
- {te = p+1;}
- break;
- case 5:
-#line 141 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (independent_cluster); }}
- break;
- case 9:
-#line 144 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (standard_cluster); }}
- break;
- case 7:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (broken_cluster); }}
- break;
- case 6:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (non_cluster); }}
- break;
- case 10:
-#line 142 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (virama_terminated_cluster); }}
- break;
- case 11:
-#line 143 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (sakot_terminated_cluster); }}
- break;
- case 8:
-#line 144 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (standard_cluster); }}
- break;
- case 13:
-#line 145 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
- break;
- case 12:
-#line 146 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (numeral_cluster); }}
- break;
- case 14:
-#line 147 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (symbol_cluster); }}
- break;
- case 17:
-#line 148 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (hieroglyph_cluster); }}
- break;
- case 15:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
- break;
- case 16:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (non_cluster); }}
- break;
- case 1:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
- break;
-#line 460 "hb-ot-shape-complex-use-machine.hh"
- }
-
-_again:
- switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 3:
+ {te = p+1;}}
+
+#line 508 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 5: {
+ {
+#line 163 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 163 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_independent_cluster); }
+ }}
+
+#line 521 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 9: {
+ {
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_standard_cluster); }
+ }}
+
+#line 534 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 7: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 547 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 6: {
+ {
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_non_cluster); }
+ }}
+
+#line 560 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 10: {
+ {
+#line 164 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 164 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_virama_terminated_cluster); }
+ }}
+
+#line 573 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 11: {
+ {
+#line 165 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 165 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_sakot_terminated_cluster); }
+ }}
+
+#line 586 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 8: {
+ {
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_standard_cluster); }
+ }}
+
+#line 599 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 13: {
+ {
+#line 167 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 167 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_number_joiner_terminated_cluster); }
+ }}
+
+#line 612 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 12: {
+ {
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_numeral_cluster); }
+ }}
+
+#line 625 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 14: {
+ {
+#line 169 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 169 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_symbol_cluster); }
+ }}
+
+#line 638 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 17: {
+ {
+#line 170 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 170 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_hieroglyph_cluster); }
+ }}
+
+#line 651 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 15: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 664 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 16: {
+ {
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_non_cluster); }
+ }}
+
+#line 677 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 1: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {p = ((te))-1;
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 691 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ }
+
+ if ( p == eof ) {
+ if ( cs >= 2 )
+ goto _out;
+ }
+ else {
+ switch ( _use_syllable_machine_to_state_actions[cs] ) {
+ case 3: {
+ {
#line 1 "NONE"
- {ts = 0;}
- break;
-#line 469 "hb-ot-shape-complex-use-machine.hh"
+ {ts = 0;}}
+
+#line 711 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ p += 1;
+ goto _resume;
+ }
+ _out: {}
}
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _use_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 203 "hb-ot-shape-complex-use-machine.rl"
-
+
+#line 265 "hb-ot-shape-complex-use-machine.rl"
+
}
#undef found_syllable
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
index df3652b18a..a35894ce81 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
@@ -31,56 +31,57 @@
* UnicodeData.txt does not have a header.
*/
-#include "hb.hh"
+#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-#ifndef HB_NO_OT_SHAPE
+#include "hb.hh"
-#include "hb-ot-shape-complex-use.hh"
+#include "hb-ot-shape-complex-use-machine.hh"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define B USE_B /* BASE */
-#define CS USE_CS /* CONS_WITH_STACKER */
-#define G USE_G /* HIEROGLYPH */
-#define GB USE_GB /* BASE_OTHER */
-#define H USE_H /* HALANT */
-#define HN USE_HN /* HALANT_NUM */
-#define HVM USE_HVM /* HALANT_OR_VOWEL_MODIFIER */
-#define J USE_J /* HIEROGLYPH_JOINER */
-#define N USE_N /* BASE_NUM */
-#define O USE_O /* OTHER */
-#define R USE_R /* REPHA */
-#define S USE_S /* SYM */
-#define SB USE_SB /* HIEROGLYPH_SEGMENT_BEGIN */
-#define SE USE_SE /* HIEROGLYPH_SEGMENT_END */
-#define SUB USE_SUB /* CONS_SUB */
-#define Sk USE_Sk /* SAKOT */
-#define ZWNJ USE_ZWNJ /* ZWNJ */
-#define CMAbv USE_CMAbv
-#define CMBlw USE_CMBlw
-#define FAbv USE_FAbv
-#define FBlw USE_FBlw
-#define FPst USE_FPst
-#define FMAbv USE_FMAbv
-#define FMBlw USE_FMBlw
-#define FMPst USE_FMPst
-#define MAbv USE_MAbv
-#define MBlw USE_MBlw
-#define MPst USE_MPst
-#define MPre USE_MPre
-#define SMAbv USE_SMAbv
-#define SMBlw USE_SMBlw
-#define VAbv USE_VAbv
-#define VBlw USE_VBlw
-#define VPst USE_VPst
-#define VPre USE_VPre
-#define VMAbv USE_VMAbv
-#define VMBlw USE_VMBlw
-#define VMPst USE_VMPst
-#define VMPre USE_VMPre
+#define B USE(B) /* BASE */
+#define CS USE(CS) /* CONS_WITH_STACKER */
+#define G USE(G) /* HIEROGLYPH */
+#define GB USE(GB) /* BASE_OTHER */
+#define H USE(H) /* HALANT */
+#define HN USE(HN) /* HALANT_NUM */
+#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */
+#define J USE(J) /* HIEROGLYPH_JOINER */
+#define N USE(N) /* BASE_NUM */
+#define O USE(O) /* OTHER */
+#define R USE(R) /* REPHA */
+#define S USE(S) /* SYM */
+#define SB USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
+#define SE USE(SE) /* HIEROGLYPH_SEGMENT_END */
+#define SUB USE(SUB) /* CONS_SUB */
+#define Sk USE(Sk) /* SAKOT */
+#define ZWNJ USE(ZWNJ) /* ZWNJ */
+#define CMAbv USE(CMAbv)
+#define CMBlw USE(CMBlw)
+#define FAbv USE(FAbv)
+#define FBlw USE(FBlw)
+#define FPst USE(FPst)
+#define FMAbv USE(FMAbv)
+#define FMBlw USE(FMBlw)
+#define FMPst USE(FMPst)
+#define MAbv USE(MAbv)
+#define MBlw USE(MBlw)
+#define MPst USE(MPst)
+#define MPre USE(MPre)
+#define SMAbv USE(SMAbv)
+#define SMBlw USE(SMBlw)
+#define VAbv USE(VAbv)
+#define VBlw USE(VBlw)
+#define VPst USE(VPst)
+#define VPre USE(VPre)
+#define VMAbv USE(VMAbv)
+#define VMBlw USE(VMBlw)
+#define VMPst USE(VMPst)
+#define VMPre USE(VMPre)
#pragma GCC diagnostic pop
-static const USE_TABLE_ELEMENT_TYPE use_table[] = {
+static const uint8_t use_table[] = {
#define use_offset_0x0028u 0
@@ -767,7 +768,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11710 */ B, B, B, B, B, B, B, B, B, B, B, O, O, MBlw, MPre, MAbv,
- /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VMAbv, O, O, O, O,
+ /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
/* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
#define use_offset_0x11800u 5848
@@ -1066,7 +1067,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
}; /* Table items: 8824; occupancy: 79% */
-USE_TABLE_ELEMENT_TYPE
+static inline uint8_t
hb_use_get_category (hb_codepoint_t u)
{
switch (u >> 12)
@@ -1154,7 +1155,7 @@ hb_use_get_category (hb_codepoint_t u)
default:
break;
}
- return USE_O;
+ return USE(O);
}
#undef B
@@ -1198,5 +1199,5 @@ hb_use_get_category (hb_codepoint_t u)
#undef VMPre
-#endif
+#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
index 8ac569d8bf..0d0b7e771e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
@@ -30,14 +30,12 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-use.hh"
+#include "hb-ot-shape-complex-use-machine.hh"
+#include "hb-ot-shape-complex-use-table.hh"
#include "hb-ot-shape-complex-arabic.hh"
#include "hb-ot-shape-complex-arabic-joining-list.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
-/* buffer var allocations */
-#define use_category() complex_var_u8_1()
-
/*
* Universal Shaping Engine.
@@ -69,11 +67,11 @@ use_topographical_features[] =
};
/* Same order as use_topographical_features. */
enum joining_form_t {
- USE_ISOL,
- USE_INIT,
- USE_MEDI,
- USE_FINA,
- _USE_NONE
+ JOINING_FORM_ISOL,
+ JOINING_FORM_INIT,
+ JOINING_FORM_MEDI,
+ JOINING_FORM_FINA,
+ _JOINING_FORM_NONE
};
static const hb_tag_t
use_other_features[] =
@@ -186,22 +184,6 @@ data_destroy_use (void *data)
free (data);
}
-enum use_syllable_type_t {
- use_independent_cluster,
- use_virama_terminated_cluster,
- use_sakot_terminated_cluster,
- use_standard_cluster,
- use_number_joiner_terminated_cluster,
- use_numeral_cluster,
- use_symbol_cluster,
- use_hieroglyph_cluster,
- use_broken_cluster,
- use_non_cluster,
-};
-
-#include "hb-ot-shape-complex-use-machine.hh"
-
-
static void
setup_masks_use (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@@ -239,7 +221,7 @@ setup_rphf_mask (const hb_ot_shape_plan_t *plan,
foreach_syllable (buffer, start, end)
{
- unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
+ unsigned int limit = info[start].use_category() == USE(R) ? 1 : hb_min (3u, end - start);
for (unsigned int i = start; i < start + limit; i++)
info[i].mask |= mask;
}
@@ -253,7 +235,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
if (use_plan->arabic_plan)
return;
- static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
+ static_assert ((JOINING_FORM_INIT < 4 && JOINING_FORM_ISOL < 4 && JOINING_FORM_MEDI < 4 && JOINING_FORM_FINA < 4), "");
hb_mask_t masks[4], all_masks = 0;
for (unsigned int i = 0; i < 4; i++)
{
@@ -267,7 +249,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
hb_mask_t other_masks = ~all_masks;
unsigned int last_start = 0;
- joining_form_t last_form = _USE_NONE;
+ joining_form_t last_form = _JOINING_FORM_NONE;
hb_glyph_info_t *info = buffer->info;
foreach_syllable (buffer, start, end)
{
@@ -279,7 +261,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
case use_hieroglyph_cluster:
case use_non_cluster:
/* These don't join. Nothing to do. */
- last_form = _USE_NONE;
+ last_form = _JOINING_FORM_NONE;
break;
case use_virama_terminated_cluster:
@@ -289,18 +271,18 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
case use_numeral_cluster:
case use_broken_cluster:
- bool join = last_form == USE_FINA || last_form == USE_ISOL;
+ bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
if (join)
{
/* Fixup previous syllable's form. */
- last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
+ last_form = last_form == JOINING_FORM_FINA ? JOINING_FORM_MEDI : JOINING_FORM_INIT;
for (unsigned int i = last_start; i < start; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
}
/* Form for this syllable. */
- last_form = join ? USE_FINA : USE_ISOL;
+ last_form = join ? JOINING_FORM_FINA : JOINING_FORM_ISOL;
for (unsigned int i = start; i < end; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
@@ -336,11 +318,11 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
foreach_syllable (buffer, start, end)
{
- /* Mark a substituted repha as USE_R. */
+ /* Mark a substituted repha as USE(R). */
for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
if (_hb_glyph_info_substituted (&info[i]))
{
- info[i].use_category() = USE_R;
+ info[i].use_category() = USE(R);
break;
}
}
@@ -359,7 +341,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_substituted (&info[i]))
{
- info[i].use_category() = USE_VPre;
+ info[i].use_category() = USE(VPre);
break;
}
}
@@ -368,7 +350,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
static inline bool
is_halant_use (const hb_glyph_info_t &info)
{
- return (info.use_category() == USE_H || info.use_category() == USE_HVM) &&
+ return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
!_hb_glyph_info_ligated (&info);
}
@@ -387,24 +369,24 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
hb_glyph_info_t *info = buffer->info;
-#define POST_BASE_FLAGS64 (FLAG64 (USE_FAbv) | \
- FLAG64 (USE_FBlw) | \
- FLAG64 (USE_FPst) | \
- FLAG64 (USE_MAbv) | \
- FLAG64 (USE_MBlw) | \
- FLAG64 (USE_MPst) | \
- FLAG64 (USE_MPre) | \
- FLAG64 (USE_VAbv) | \
- FLAG64 (USE_VBlw) | \
- FLAG64 (USE_VPst) | \
- FLAG64 (USE_VPre) | \
- FLAG64 (USE_VMAbv) | \
- FLAG64 (USE_VMBlw) | \
- FLAG64 (USE_VMPst) | \
- FLAG64 (USE_VMPre))
+#define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
+ FLAG64 (USE(FBlw)) | \
+ FLAG64 (USE(FPst)) | \
+ FLAG64 (USE(MAbv)) | \
+ FLAG64 (USE(MBlw)) | \
+ FLAG64 (USE(MPst)) | \
+ FLAG64 (USE(MPre)) | \
+ FLAG64 (USE(VAbv)) | \
+ FLAG64 (USE(VBlw)) | \
+ FLAG64 (USE(VPst)) | \
+ FLAG64 (USE(VPre)) | \
+ FLAG64 (USE(VMAbv)) | \
+ FLAG64 (USE(VMBlw)) | \
+ FLAG64 (USE(VMPst)) | \
+ FLAG64 (USE(VMPre)))
/* Move things forward. */
- if (info[start].use_category() == USE_R && end - start > 1)
+ if (info[start].use_category() == USE(R) && end - start > 1)
{
/* Got a repha. Reorder it towards the end, but before the first post-base
* glyph. */
@@ -441,7 +423,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
* shift things in between forward. */
j = i + 1;
}
- else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+ else if (((flag) & (FLAG (USE(VPre)) | FLAG (USE(VMPre)))) &&
/* Only move the first component of a MultipleSubst. */
0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
j < i)
@@ -454,76 +436,22 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
}
}
-static inline void
-insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == use_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
- return;
- dottedcircle.use_category() = hb_use_get_category (0x25CC);
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().use_category() == USE_R)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering USE")) {
- insert_dotted_circles_use (plan, font, buffer);
+ if (buffer->message (font, "start reordering USE"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ use_broken_cluster,
+ USE(B),
+ USE(R));
- foreach_syllable (buffer, start, end)
- reorder_syllable_use (buffer, start, end);
+ foreach_syllable (buffer, start, end)
+ reorder_syllable_use (buffer, start, end);
- (void) buffer->message (font, "end reordering USE");
+ (void) buffer->message (font, "end reordering USE");
}
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh
deleted file mode 100644
index 788fb6b6ac..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright © 2015 Mozilla Foundation.
- * Copyright © 2015 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_HH
-
-#include "hb.hh"
-
-
-#include "hb-ot-shape-complex.hh"
-
-
-#define USE_TABLE_ELEMENT_TYPE uint8_t
-
-/* Cateories used in the Universal Shaping Engine spec:
- * https://docs.microsoft.com/en-us/typography/script-development/use
- */
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum use_category_t {
- USE_O = 0, /* OTHER */
-
- USE_B = 1, /* BASE */
- USE_N = 4, /* BASE_NUM */
- USE_GB = 5, /* BASE_OTHER */
- USE_SUB = 11, /* CONS_SUB */
- USE_H = 12, /* HALANT */
-
- USE_HN = 13, /* HALANT_NUM */
- USE_ZWNJ = 14, /* Zero width non-joiner */
- USE_R = 18, /* REPHA */
- USE_S = 19, /* SYM */
- USE_CS = 43, /* CONS_WITH_STACKER */
-
- /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
- USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */
-
- USE_Sk = 48, /* SAKOT */
- USE_G = 49, /* HIEROGLYPH */
- USE_J = 50, /* HIEROGLYPH_JOINER */
- USE_SB = 51, /* HIEROGLYPH_SEGMENT_BEGIN */
- USE_SE = 52, /* HIEROGLYPH_SEGMENT_END */
-
- USE_FAbv = 24, /* CONS_FINAL_ABOVE */
- USE_FBlw = 25, /* CONS_FINAL_BELOW */
- USE_FPst = 26, /* CONS_FINAL_POST */
- USE_MAbv = 27, /* CONS_MED_ABOVE */
- USE_MBlw = 28, /* CONS_MED_BELOW */
- USE_MPst = 29, /* CONS_MED_POST */
- USE_MPre = 30, /* CONS_MED_PRE */
- USE_CMAbv = 31, /* CONS_MOD_ABOVE */
- USE_CMBlw = 32, /* CONS_MOD_BELOW */
- USE_VAbv = 33, /* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
- USE_VBlw = 34, /* VOWEL_BELOW / VOWEL_BELOW_POST */
- USE_VPst = 35, /* VOWEL_POST UIPC = Right */
- USE_VPre = 22, /* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
- USE_VMAbv = 37, /* VOWEL_MOD_ABOVE */
- USE_VMBlw = 38, /* VOWEL_MOD_BELOW */
- USE_VMPst = 39, /* VOWEL_MOD_POST */
- USE_VMPre = 23, /* VOWEL_MOD_PRE */
- USE_SMAbv = 41, /* SYM_MOD_ABOVE */
- USE_SMBlw = 42, /* SYM_MOD_BELOW */
- USE_FMAbv = 45, /* CONS_FINAL_MOD UIPC = Top */
- USE_FMBlw = 46, /* CONS_FINAL_MOD UIPC = Bottom */
- USE_FMPst = 47, /* CONS_FINAL_MOD UIPC = Not_Applicable */
-};
-
-HB_INTERNAL USE_TABLE_ELEMENT_TYPE
-hb_use_get_category (hb_codepoint_t u);
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
index 1af546e4fa..1037626998 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -23,15 +23,15 @@
static void
_output_dotted_circle (hb_buffer_t *buffer)
{
- hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
- _hb_glyph_info_reset_continuation (&dottedcircle);
+ (void) buffer->output_glyph (0x25CCu);
+ _hb_glyph_info_reset_continuation (&buffer->prev());
}
static void
_output_with_dotted_circle (hb_buffer_t *buffer)
{
_output_dotted_circle (buffer);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
void
@@ -51,7 +51,6 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
*
* https://github.com/harfbuzz/harfbuzz/issues/1019
*/
- bool processed = false;
buffer->clear_output ();
unsigned int count = buffer->len;
switch ((unsigned) buffer->props.script)
@@ -97,15 +96,14 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx + 2 < count &&
0x0907u == buffer->cur (2).codepoint)
{
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
matched = true;
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_BENGALI:
@@ -124,10 +122,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x09E2u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_GURMUKHI:
@@ -161,10 +158,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_GUJARATI:
@@ -186,10 +182,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0ABEu == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_ORIYA:
@@ -205,10 +200,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0B57u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TAMIL:
@@ -220,10 +214,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
matched = true;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TELUGU:
@@ -244,10 +237,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0C55u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_KANNADA:
@@ -263,10 +255,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0CCCu == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_MALAYALAM:
@@ -290,10 +281,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_SINHALA:
@@ -326,10 +316,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_BRAHMI:
@@ -348,10 +337,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x11042u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_KHUDAWADI:
@@ -370,10 +358,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TIRHUTA:
@@ -397,10 +384,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_MODI:
@@ -418,10 +404,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TAKRI:
@@ -442,21 +427,15 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x116B2u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
default:
break;
}
- if (processed)
- {
- if (buffer->idx < count)
- buffer->next_glyph ();
- buffer->swap_buffers ();
- }
+ buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
index a1a7a6a47b..19e24b9f30 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
@@ -35,8 +35,8 @@
/* buffer var allocations, used by complex shapers */
-#define complex_var_u8_0() var2.u8[2]
-#define complex_var_u8_1() var2.u8[3]
+#define complex_var_u8_category() var2.u8[2]
+#define complex_var_u8_auxiliary() var2.u8[3]
#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
@@ -186,27 +186,8 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_ARABIC:
/* Unicode-3.0 additions */
- case HB_SCRIPT_MONGOLIAN:
case HB_SCRIPT_SYRIAC:
- /* Unicode-5.0 additions */
- case HB_SCRIPT_NKO:
- case HB_SCRIPT_PHAGS_PA:
-
- /* Unicode-6.0 additions */
- case HB_SCRIPT_MANDAIC:
-
- /* Unicode-7.0 additions */
- case HB_SCRIPT_MANICHAEAN:
- case HB_SCRIPT_PSALTER_PAHLAVI:
-
- /* Unicode-9.0 additions */
- case HB_SCRIPT_ADLAM:
-
- /* Unicode-11.0 additions */
- case HB_SCRIPT_HANIFI_ROHINGYA:
- case HB_SCRIPT_SOGDIAN:
-
/* For Arabic script, use the Arabic shaper even if no OT script tag was found.
* This is because we do fallback shaping for Arabic script (and not others).
* But note that Arabic shaping is applicable only to horizontal layout; for
@@ -284,8 +265,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_myanmar;
- /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
+#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
case HB_SCRIPT_MYANMAR_ZAWGYI:
+ /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
return &_hb_ot_complex_shaper_myanmar_zawgyi;
@@ -294,7 +276,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_TIBETAN:
/* Unicode-3.0 additions */
- //case HB_SCRIPT_MONGOLIAN:
+ case HB_SCRIPT_MONGOLIAN:
//case HB_SCRIPT_SINHALA:
/* Unicode-3.2 additions */
@@ -315,8 +297,8 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-5.0 additions */
case HB_SCRIPT_BALINESE:
- //case HB_SCRIPT_NKO:
- //case HB_SCRIPT_PHAGS_PA:
+ case HB_SCRIPT_NKO:
+ case HB_SCRIPT_PHAGS_PA:
/* Unicode-5.1 additions */
case HB_SCRIPT_CHAM:
@@ -337,7 +319,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-6.0 additions */
case HB_SCRIPT_BATAK:
case HB_SCRIPT_BRAHMI:
- //case HB_SCRIPT_MANDAIC:
+ case HB_SCRIPT_MANDAIC:
/* Unicode-6.1 additions */
case HB_SCRIPT_CHAKMA:
@@ -351,10 +333,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_KHOJKI:
case HB_SCRIPT_KHUDAWADI:
case HB_SCRIPT_MAHAJANI:
- //case HB_SCRIPT_MANICHAEAN:
+ case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MODI:
case HB_SCRIPT_PAHAWH_HMONG:
- //case HB_SCRIPT_PSALTER_PAHLAVI:
+ case HB_SCRIPT_PSALTER_PAHLAVI:
case HB_SCRIPT_SIDDHAM:
case HB_SCRIPT_TIRHUTA:
@@ -363,7 +345,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_MULTANI:
/* Unicode-9.0 additions */
- //case HB_SCRIPT_ADLAM:
+ case HB_SCRIPT_ADLAM:
case HB_SCRIPT_BHAIKSUKI:
case HB_SCRIPT_MARCHEN:
case HB_SCRIPT_NEWA:
@@ -376,11 +358,11 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-11.0 additions */
case HB_SCRIPT_DOGRA:
case HB_SCRIPT_GUNJALA_GONDI:
- //case HB_SCRIPT_HANIFI_ROHINGYA:
+ case HB_SCRIPT_HANIFI_ROHINGYA:
case HB_SCRIPT_MAKASAR:
case HB_SCRIPT_MEDEFAIDRIN:
case HB_SCRIPT_OLD_SOGDIAN:
- //case HB_SCRIPT_SOGDIAN:
+ case HB_SCRIPT_SOGDIAN:
/* Unicode-12.0 additions */
case HB_SCRIPT_ELYMAIC:
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
index 3eabae1b45..778b5b8bd8 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -101,8 +101,9 @@ set_glyph (hb_glyph_info_t &info, hb_font_t *font)
static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
+ /* This is very confusing indeed. */
buffer->cur().glyph_index() = glyph;
- buffer->output_glyph (unichar); /* This is very confusing indeed. */
+ (void) buffer->output_glyph (unichar);
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
}
@@ -110,7 +111,7 @@ static inline void
next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
static inline void
@@ -229,30 +230,35 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
{
hb_codepoint_t unicode = buffer->cur().codepoint;
- buffer->replace_glyphs (2, 1, &unicode);
+ (void) buffer->replace_glyphs (2, 1, &unicode);
}
else
{
/* Just pass on the two characters separately, let GSUB do its magic. */
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
/* Skip any further variation selectors. */
- while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+ while (buffer->idx < end &&
+ buffer->successful &&
+ unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
{
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
- } else {
+ }
+ else
+ {
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
- if (likely (buffer->idx < end)) {
+ if (likely (buffer->idx < end))
+ {
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
@@ -348,7 +354,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
sizeof (buffer->info[0]),
&buffer->cur().glyph_index(),
sizeof (buffer->info[0]));
- buffer->next_glyphs (done);
+ if (unlikely (!buffer->next_glyphs (done))) break;
}
while (buffer->idx < end && buffer->successful)
decompose_current_character (&c, might_short_circuit);
@@ -419,6 +425,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
/* Third round, recompose */
if (!all_simple &&
+ buffer->successful &&
(mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT))
{
@@ -428,8 +435,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
count = buffer->len;
unsigned int starter = 0;
- buffer->next_glyph ();
- while (buffer->idx < count && buffer->successful)
+ (void) buffer->next_glyph ();
+ while (buffer->idx < count /* No need for: && buffer->successful */)
{
hb_codepoint_t composed, glyph;
if (/* We don't try to compose a non-mark character with it's preceding starter.
@@ -451,9 +458,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
font->get_nominal_glyph (composed, &glyph))
{
/* Composes. */
- buffer->next_glyph (); /* Copy to out-buffer. */
- if (unlikely (!buffer->successful))
- return;
+ if (unlikely (!buffer->next_glyph ())) break; /* Copy to out-buffer. */
buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */
/* Modify starter and carry on. */
@@ -466,7 +471,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
}
/* Blocked, or doesn't compose. */
- buffer->next_glyph ();
+ if (unlikely (!buffer->next_glyph ())) break;
if (info_cc (buffer->prev()) == 0)
starter = buffer->out_len - 1;
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 7d90558458..86ab0b4268 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -534,9 +534,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
- buffer->output_info (info);
- while (buffer->idx < buffer->len && buffer->successful)
- buffer->next_glyph ();
+ (void) buffer->output_info (info);
buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.h b/thirdparty/harfbuzz/src/hb-ot-shape.h
index 7b1bcc0637..afdff72833 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.h
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
index f1c391cf0e..87830b5462 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2020-11-17 08:21 AM" />
- * File-Date: 2020-09-29
+ * <meta name="updated_at" content="2021-02-12 04:08 PM" />
+ * File-Date: 2021-03-05
*/
#ifndef HB_OT_TAG_TABLE_HH
@@ -169,6 +169,7 @@ static const LangTag ot_languages[] = {
{"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */
{"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */
{"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */
+ {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */
{"bli", HB_TAG_NONE }, /* Bolia != Baluchi */
{"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */
{"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */
@@ -358,6 +359,7 @@ static const LangTag ot_languages[] = {
{"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */
{"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
+/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */
{"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */
/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */
@@ -834,6 +836,7 @@ static const LangTag ot_languages[] = {
{"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */
{"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */
{"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */
+ {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */
{"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
{"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */
@@ -990,7 +993,7 @@ static const LangTag ot_languages[] = {
/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
{"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */
- {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni -> Sutu */
+ {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */
{"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */
{"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */
{"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */
@@ -1520,6 +1523,8 @@ static const LangTag ot_languages[] = {
{"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */
{"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */
{"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */
+ {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */
+ {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */
{"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */
/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */
{"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */
@@ -2808,6 +2813,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("hnd", -1); /* Southern Hindko */
case HB_TAG('H','Y','E',' '): /* Armenian */
return hb_language_from_string ("hyw", -1); /* Western Armenian */
+ case HB_TAG('I','B','A',' '): /* Iban */
+ return hb_language_from_string ("iba", -1); /* Iban */
case HB_TAG('I','J','O',' '): /* Ijo */
return hb_language_from_string ("ijo", -1); /* Ijo [family] */
case HB_TAG('I','N','U',' '): /* Inuktitut */
@@ -2892,6 +2899,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */
return hb_language_from_string ("sr", -1); /* Serbian */
+ case HB_TAG('S','X','T',' '): /* Sutu */
+ return hb_language_from_string ("xnj", -1); /* Ngoni (Tanzania) */
case HB_TAG('S','Y','R',' '): /* Syriac */
return hb_language_from_string ("syr", -1); /* Syriac [macrolanguage] */
case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index 19bd3639d3..fc145a41f7 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -164,6 +164,15 @@ hb_ot_all_tags_from_script (hb_script_t script,
*count = i;
}
+/**
+ * hb_ot_tag_to_script:
+ * @tag: a script tag
+ *
+ * Converts a script tag to an #hb_script_t.
+ *
+ * Return value: The #hb_script_t corresponding to @tag.
+ *
+ **/
hb_script_t
hb_ot_tag_to_script (hb_tag_t tag)
{
@@ -351,13 +360,13 @@ parse_private_use_subtag (const char *private_use_subtag,
* hb_ot_tags_from_script_and_language:
* @script: an #hb_script_t to convert.
* @language: an #hb_language_t to convert.
- * @script_count: (allow-none): maximum number of script tags to retrieve (IN)
+ * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
* and actual number of script tags retrieved (OUT)
- * @script_tags: (out) (allow-none): array of size at least @script_count to store the
+ * @script_tags: (out) (optional): array of size at least @script_count to store the
* script tag results
- * @language_count: (allow-none): maximum number of language tags to retrieve
+ * @language_count: (inout) (optional): maximum number of language tags to retrieve
* (IN) and actual number of language tags retrieved (OUT)
- * @language_tags: (out) (allow-none): array of size at least @language_count to store
+ * @language_tags: (out) (optional): array of size at least @language_count to store
* the language tag results
*
* Converts an #hb_script_t and an #hb_language_t to script and language tags.
@@ -424,10 +433,12 @@ hb_ot_tags_from_script_and_language (hb_script_t script,
/**
* hb_ot_tag_to_language:
+ * @tag: an language tag
*
+ * Converts a language tag to an #hb_language_t.
*
- *
- * Return value: (transfer none):
+ * Return value: (transfer none) (nullable):
+ * The #hb_language_t corresponding to @tag.
*
* Since: 0.9.2
**/
@@ -478,9 +489,9 @@ hb_ot_tag_to_language (hb_tag_t tag)
* hb_ot_tags_to_script_and_language:
* @script_tag: a script tag
* @language_tag: a language tag
- * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT).
- * @language: (allow-none): the #hb_language_t corresponding to @script_tag and
- * @language_tag (OUT).
+ * @script: (out) (optional): the #hb_script_t corresponding to @script_tag.
+ * @language: (out) (optional): the #hb_language_t corresponding to @script_tag and
+ * @language_tag.
*
* Converts a script tag and a language tag to an #hb_script_t and an
* #hb_language_t.
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
index 4d4e6dcae4..7e4eaaad95 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
@@ -652,8 +652,8 @@ no_more_gaps:
/* apply specified / inferred deltas to points */
for (unsigned int i = 0; i < points.length; i++)
{
- points[i].x += roundf (deltas[i].x);
- points[i].y += roundf (deltas[i].y);
+ points[i].x += deltas[i].x;
+ points[i].y += deltas[i].y;
}
} while (iterator.move_to_next ());
diff --git a/thirdparty/harfbuzz/src/hb-ot-var.cc b/thirdparty/harfbuzz/src/hb-ot-var.cc
index 1fe57383c0..6b42b45cd9 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-var.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face includes any OpenType variation data in the `fvar` table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.4.2
**/
@@ -87,7 +87,7 @@ hb_ot_var_get_axis_count (hb_face_t *face)
* hb_ot_var_get_axes:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first lookup to retrieve
- * @axes_count: (inout) (allow-none): Input = the maximum number of variation axes to return;
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
* Output = the actual number of variation axes returned (may be zero)
* @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
*
@@ -133,7 +133,7 @@ hb_ot_var_find_axis (hb_face_t *face,
* hb_ot_var_get_axis_infos:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first lookup to retrieve
- * @axes_count: (inout) (allow-none): Input = the maximum number of variation axes to return;
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
* Output = the actual number of variation axes returned (may be zero)
* @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
*
@@ -162,7 +162,7 @@ hb_ot_var_get_axis_infos (hb_face_t *face,
* Fetches the variation-axis information corresponding to the specified axis tag
* in the specified face.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.2.0
**/
@@ -237,7 +237,7 @@ hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face,
* hb_ot_var_named_instance_get_design_coords:
* @face: The #hb_face_t to work on
* @instance_index: The index of the named instance to query
- * @coords_length: (inout) (allow-none): Input = the maximum number of coordinates to return;
+ * @coords_length: (inout) (optional): Input = the maximum number of coordinates to return;
* Output = the actual number of coordinates returned (may be zero)
* @coords: (out) (array length=coords_length): The array of coordinates found for the query
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-var.h b/thirdparty/harfbuzz/src/hb-ot-var.h
index ef2ca0a716..ce201d3b4f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var.h
+++ b/thirdparty/harfbuzz/src/hb-ot-var.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -36,34 +36,38 @@
HB_BEGIN_DECLS
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_ITALIC: Registered tag for the roman/italic axis
+ * HB_OT_TAG_VAR_AXIS_ITALIC:
+ *
+ * Registered tag for the roman/italic axis.
*/
#define HB_OT_TAG_VAR_AXIS_ITALIC HB_TAG('i','t','a','l')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE: Registered tag for the optical-size axis
+ * HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE:
*
+ * Registered tag for the optical-size axis.
* <note>Note: The optical-size axis supersedes the OpenType `size` feature.</note>
*/
#define HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE HB_TAG('o','p','s','z')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_SLANT: Registered tag for the slant axis
+ * HB_OT_TAG_VAR_AXIS_SLANT:
+ *
+ * Registered tag for the slant axis
*/
#define HB_OT_TAG_VAR_AXIS_SLANT HB_TAG('s','l','n','t')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_WIDTH: Registered tag for the width axis
+ * HB_OT_TAG_VAR_AXIS_WIDTH:
+ *
+ * Registered tag for the width axis.
*/
#define HB_OT_TAG_VAR_AXIS_WIDTH HB_TAG('w','d','t','h')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_WEIGHT: Registered tag for the weight axis
+ * HB_OT_TAG_VAR_AXIS_WEIGHT:
+ *
+ * Registered tag for the weight axis.
*/
#define HB_OT_TAG_VAR_AXIS_WEIGHT HB_TAG('w','g','h','t')
@@ -88,11 +92,14 @@ hb_ot_var_get_axis_count (hb_face_t *face);
* hb_ot_var_axis_flags_t:
* @HB_OT_VAR_AXIS_FLAG_HIDDEN: The axis should not be exposed directly in user interfaces.
*
+ * Flags for #hb_ot_var_axis_info_t.
+ *
* Since: 2.2.0
*/
typedef enum { /*< flags >*/
HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u,
+ /*< private >*/
_HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_var_axis_flags_t;
diff --git a/thirdparty/harfbuzz/src/hb-sanitize.hh b/thirdparty/harfbuzz/src/hb-sanitize.hh
index 024b4d1c99..1675e8448a 100644
--- a/thirdparty/harfbuzz/src/hb-sanitize.hh
+++ b/thirdparty/harfbuzz/src/hb-sanitize.hh
@@ -73,7 +73,7 @@
* === The sanitize() contract ===
*
* The sanitize() method of each object type shall return true if it's safe to
- * call other methods of the object, and false otherwise.
+ * call other methods of the object, and %false otherwise.
*
* Note that what sanitize() checks for might align with what the specification
* describes as valid table data, but does not have to be. In particular, we
@@ -113,8 +113,8 @@
#ifndef HB_SANITIZE_MAX_OPS_MAX
#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
#endif
-#ifndef HB_SANITIZE_MAX_SUTABLES
-#define HB_SANITIZE_MAX_SUTABLES 0x4000
+#ifndef HB_SANITIZE_MAX_SUBTABLES
+#define HB_SANITIZE_MAX_SUBTABLES 0x4000
#endif
struct hb_sanitize_context_t :
@@ -139,7 +139,7 @@ struct hb_sanitize_context_t :
bool visit_subtables (unsigned count)
{
max_subtables += count;
- return max_subtables < HB_SANITIZE_MAX_SUTABLES;
+ return max_subtables < HB_SANITIZE_MAX_SUBTABLES;
}
private:
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index 4566153a59..fe29bdf96e 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -256,10 +256,11 @@ struct hb_serialize_context_t
packed.push (obj);
- if (unlikely (packed.in_error ())) {
- // obj wasn't successfully added to packed, so clean it up otherwise it's
- // links will be leaked.
- propagate_error (packed);
+ if (unlikely (!propagate_error (packed)))
+ {
+ /* Obj wasn't successfully added to packed, so clean it up otherwise its
+ * links will be leaked. When we use constructor/destructors properly, we
+ * can remove these. */
obj->fini ();
return 0;
}
@@ -523,7 +524,7 @@ struct hb_serialize_context_t
template <typename T>
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
{
- auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
+ auto &off = * ((BEInt<T> *) (parent->head + link.position));
assert (0 == off);
check_assign (off, offset);
}
diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc
index 3b4059ad32..86bf70034c 100644
--- a/thirdparty/harfbuzz/src/hb-set.cc
+++ b/thirdparty/harfbuzz/src/hb-set.cc
@@ -117,7 +117,7 @@ hb_set_destroy (hb_set_t *set)
* @set: A set
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified set.
@@ -162,7 +162,7 @@ hb_set_get_user_data (hb_set_t *set,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, false otherwise
+ * Return value: %true if allocation succeeded, %false otherwise
*
* Since: 0.9.2
**/
@@ -183,6 +183,9 @@ hb_set_allocation_successful (const hb_set_t *set)
void
hb_set_clear (hb_set_t *set)
{
+ if (unlikely (hb_object_is_immutable (set)))
+ return;
+
set->clear ();
}
@@ -209,7 +212,7 @@ hb_set_is_empty (const hb_set_t *set)
*
* Tests whether @codepoint belongs to @set.
*
- * Return value: %true if @codepoint is in @set, false otherwise
+ * Return value: %true if @codepoint is in @set, %false otherwise
*
* Since: 0.9.2
**/
@@ -298,7 +301,7 @@ hb_set_del_range (hb_set_t *set,
* Tests whether @set and @other are equal (contain the same
* elements).
*
- * Return value: %TRUE if the two sets are equal, %FALSE otherwise.
+ * Return value: %true if the two sets are equal, %false otherwise.
*
* Since: 0.9.7
**/
@@ -316,7 +319,7 @@ hb_set_is_equal (const hb_set_t *set,
*
* Tests whether @set is a subset of @larger_set.
*
- * Return value: %TRUE if the @set is a subset of (or equal to) @larger_set, %FALSE otherwise.
+ * Return value: %true if the @set is a subset of (or equal to) @larger_set, %false otherwise.
*
* Since: 1.8.1
**/
@@ -447,7 +450,7 @@ hb_set_get_population (const hb_set_t *set)
*
* Finds the smallest element in the set.
*
- * Return value: minimum of @set, or %HB_SET_VALUE_INVALID if @set is empty.
+ * Return value: minimum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
*
* Since: 0.9.7
**/
@@ -463,7 +466,7 @@ hb_set_get_min (const hb_set_t *set)
*
* Finds the largest element in the set.
*
- * Return value: maximum of @set, or %HB_SET_VALUE_INVALID if @set is empty.
+ * Return value: maximum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
*
* Since: 0.9.7
**/
@@ -481,9 +484,9 @@ hb_set_get_max (const hb_set_t *set)
*
* Fetches the next element in @set that is greater than current value of @codepoint.
*
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next value, false otherwise
+ * Return value: %true if there was a next value, %false otherwise
*
* Since: 0.9.2
**/
@@ -502,9 +505,9 @@ hb_set_next (const hb_set_t *set,
*
* Fetches the previous element in @set that is lower than current value of @codepoint.
*
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous value, false otherwise
+ * Return value: %true if there was a previous value, %false otherwise
*
* Since: 1.8.0
**/
@@ -525,9 +528,9 @@ hb_set_previous (const hb_set_t *set,
* Fetches the next consecutive range of elements in @set that
* are greater than current value of @last.
*
- * Set @last to %HB_SET_VALUE_INVALID to get started.
+ * Set @last to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next range, false otherwise
+ * Return value: %true if there was a next range, %false otherwise
*
* Since: 0.9.7
**/
@@ -549,9 +552,9 @@ hb_set_next_range (const hb_set_t *set,
* Fetches the previous consecutive range of elements in @set that
* are greater than current value of @last.
*
- * Set @first to %HB_SET_VALUE_INVALID to get started.
+ * Set @first to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous range, false otherwise
+ * Return value: %true if there was a previous range, %false otherwise
*
* Since: 1.8.0
**/
diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h
index cafc36dbad..0ad27f4bbd 100644
--- a/thirdparty/harfbuzz/src/hb-set.h
+++ b/thirdparty/harfbuzz/src/hb-set.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,7 +36,11 @@
HB_BEGIN_DECLS
-/*
+/**
+ * HB_SET_VALUE_INVALID:
+ *
+ * Unset #hb_set_t value.
+ *
* Since: 0.9.21
*/
#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh
index b6e2086a2e..ae8b5eb10f 100644
--- a/thirdparty/harfbuzz/src/hb-set.hh
+++ b/thirdparty/harfbuzz/src/hb-set.hh
@@ -244,7 +244,7 @@ struct hb_set_t
bool resize (unsigned int count)
{
- if (unlikely (!successful)) return false;
+ if (unlikely (count > pages.length && !successful)) return false;
if (!pages.resize (count) || !page_map.resize (count))
{
pages.resize (page_map.length);
@@ -256,19 +256,14 @@ struct hb_set_t
void reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
- clear ();
successful = true;
+ clear ();
}
void clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
- population = 0;
- page_map.resize (0);
- pages.resize (0);
+ if (resize (0))
+ population = 0;
}
bool is_empty () const
{
@@ -278,6 +273,7 @@ struct hb_set_t
return false;
return true;
}
+ explicit operator bool () const { return !is_empty (); }
void dirty () { population = UINT_MAX; }
@@ -389,6 +385,11 @@ struct hb_set_t
{
if (ds <= de)
{
+ // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+ // before attempting to rewrite the page map.
+ hb_vector_t<unsigned> compact_workspace;
+ if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
unsigned int write_index = 0;
for (unsigned int i = 0; i < page_map.length; i++)
{
@@ -396,11 +397,12 @@ struct hb_set_t
if (m < ds || de < m)
page_map[write_index++] = page_map[i];
}
- compact (write_index);
+ compact (compact_workspace, write_index);
resize (write_index);
}
}
+
public:
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
@@ -512,20 +514,37 @@ struct hb_set_t
return true;
}
- void compact (unsigned int length)
+ bool allocate_compact_workspace(hb_vector_t<unsigned>& workspace)
+ {
+ if (unlikely(!workspace.resize (pages.length)))
+ {
+ successful = false;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /*
+ * workspace should be a pre-sized vector allocated to hold at exactly pages.length
+ * elements.
+ */
+ void compact (hb_vector_t<unsigned>& workspace,
+ unsigned int length)
{
- hb_vector_t<uint32_t> old_index_to_page_map_index;
- old_index_to_page_map_index.resize(pages.length);
- for (uint32_t i = 0; i < old_index_to_page_map_index.length; i++)
- old_index_to_page_map_index[i] = 0xFFFFFFFF;
+ assert(workspace.length == pages.length);
+ hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
- for (uint32_t i = 0; i < length; i++)
+ hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
+ /* TODO(iter) Rewrite as dagger? */
+ for (unsigned i = 0; i < length; i++)
old_index_to_page_map_index[page_map[i].index] = i;
compact_pages (old_index_to_page_map_index);
}
- void compact_pages (const hb_vector_t<uint32_t>& old_index_to_page_map_index)
+ void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
{
unsigned int write_index = 0;
for (unsigned int i = 0; i < pages.length; i++)
@@ -543,6 +562,9 @@ struct hb_set_t
template <typename Op>
void process (const Op& op, const hb_set_t *other)
{
+ const bool passthru_left = op (1, 0);
+ const bool passthru_right = op (0, 1);
+
if (unlikely (!successful)) return;
dirty ();
@@ -554,11 +576,17 @@ struct hb_set_t
unsigned int count = 0, newCount = 0;
unsigned int a = 0, b = 0;
unsigned int write_index = 0;
+
+ // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+ // before attempting to rewrite the page map.
+ hb_vector_t<unsigned> compact_workspace;
+ if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
for (; a < na && b < nb; )
{
if (page_map[a].major == other->page_map[b].major)
{
- if (!Op::passthru_left)
+ if (!passthru_left)
{
// Move page_map entries that we're keeping from the left side set
// to the front of the page_map vector. This isn't necessary if
@@ -575,27 +603,27 @@ struct hb_set_t
}
else if (page_map[a].major < other->page_map[b].major)
{
- if (Op::passthru_left)
+ if (passthru_left)
count++;
a++;
}
else
{
- if (Op::passthru_right)
+ if (passthru_right)
count++;
b++;
}
}
- if (Op::passthru_left)
+ if (passthru_left)
count += na - a;
- if (Op::passthru_right)
+ if (passthru_right)
count += nb - b;
- if (!Op::passthru_left)
+ if (!passthru_left)
{
na = write_index;
next_page = write_index;
- compact (write_index);
+ compact (compact_workspace, write_index);
}
if (!resize (count))
@@ -619,7 +647,7 @@ struct hb_set_t
else if (page_map[a - 1].major > other->page_map[b - 1].major)
{
a--;
- if (Op::passthru_left)
+ if (passthru_left)
{
count--;
page_map[count] = page_map[a];
@@ -628,7 +656,7 @@ struct hb_set_t
else
{
b--;
- if (Op::passthru_right)
+ if (passthru_right)
{
count--;
page_map[count].major = other->page_map[b].major;
@@ -637,14 +665,14 @@ struct hb_set_t
}
}
}
- if (Op::passthru_left)
+ if (passthru_left)
while (a)
{
a--;
count--;
page_map[count] = page_map [a];
}
- if (Op::passthru_right)
+ if (passthru_right)
while (b)
{
b--;
@@ -655,6 +683,9 @@ struct hb_set_t
}
assert (!count);
if (pages.length > newCount)
+ // This resize() doesn't need to be checked because we can't get here
+ // if the set is currently in_error() and this only resizes downwards
+ // which will always succeed if the set is not in_error().
resize (newCount);
}
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc
index 65a5fc4512..0d9eaddaa6 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc
@@ -329,12 +329,12 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
* @shape_plan: A shaping plan
* @key: The user-data key to set
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given shaping plan.
*
- * Return value:
+ * Return value: %true if success, %false otherwise.
*
* Since: 0.9.7
**/
@@ -439,7 +439,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t *shape_plan,
* Executes the given shaping plan on the specified buffer, using
* the given @font and @features.
*
- * Return value:
+ * Return value: %true if success, %false otherwise.
*
* Since: 0.9.7
**/
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.h b/thirdparty/harfbuzz/src/hb-shape-plan.h
index 336524ee2f..fc7c041899 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.h
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc
index a3debce397..c442f4403b 100644
--- a/thirdparty/harfbuzz/src/hb-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-shape.cc
@@ -111,10 +111,10 @@ hb_shape_list_shapers ()
* hb_shape_full:
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @features: (array length=num_features) (nullable): an array of user
* specified #hb_feature_t or %NULL
* @num_features: the length of @features array
- * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
+ * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated
* array of shapers to use or %NULL
*
* See hb_shape() for details. If @shaper_list is not %NULL, the specified
@@ -146,7 +146,7 @@ hb_shape_full (hb_font_t *font,
* hb_shape:
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @features: (array length=num_features) (nullable): an array of user
* specified #hb_feature_t or %NULL
* @num_features: the length of @features array
*
diff --git a/thirdparty/harfbuzz/src/hb-shape.h b/thirdparty/harfbuzz/src/hb-shape.h
index 39507ff744..922f8c011e 100644
--- a/thirdparty/harfbuzz/src/hb-shape.h
+++ b/thirdparty/harfbuzz/src/hb-shape.h
@@ -26,7 +26,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-style.cc b/thirdparty/harfbuzz/src/hb-style.cc
index 86b9f7da5f..2f45d119f9 100644
--- a/thirdparty/harfbuzz/src/hb-style.cc
+++ b/thirdparty/harfbuzz/src/hb-style.cc
@@ -65,6 +65,7 @@ typedef enum {
HB_STYLE_TAG_WIDTH = HB_TAG ('w','d','t','h'),
HB_STYLE_TAG_WEIGHT = HB_TAG ('w','g','h','t'),
+ /*< private >*/
_HB_STYLE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_style_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-style.h b/thirdparty/harfbuzz/src/hb-style.h
index 1209c79e94..f5776cee58 100644
--- a/thirdparty/harfbuzz/src/hb-style.h
+++ b/thirdparty/harfbuzz/src/hb-style.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 24beada3e8..d055783a4d 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -88,10 +88,17 @@ _gsub_closure_glyphs_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gsub_lookups);
- //closure features
+ // Collect and prune features
hb_set_t feature_indices;
- gsub->closure_features (gsub_lookups, &feature_indices);
+ hb_ot_layout_collect_features (face,
+ HB_OT_TAG_GSUB,
+ nullptr,
+ nullptr,
+ nullptr,
+ &feature_indices);
+ gsub->prune_features (gsub_lookups, &feature_indices);
_remap_indexes (&feature_indices, gsub_features);
+
gsub.destroy ();
}
@@ -114,9 +121,15 @@ _gpos_closure_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gpos_lookups);
- //closure features
+ // Collect and prune features
hb_set_t feature_indices;
- gpos->closure_features (gpos_lookups, &feature_indices);
+ hb_ot_layout_collect_features (face,
+ HB_OT_TAG_GPOS,
+ nullptr,
+ nullptr,
+ nullptr,
+ &feature_indices);
+ gpos->prune_features (gpos_lookups, &feature_indices);
_remap_indexes (&feature_indices, gpos_features);
gpos.destroy ();
}
@@ -243,7 +256,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR
if (close_over_gdef)
- _collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map);
+ _collect_layout_variation_indices (plan->source,
+ plan->_glyphset_gsub,
+ plan->gpos_lookups,
+ plan->layout_variation_indices,
+ plan->layout_variation_idx_map);
#endif
#ifndef HB_NO_SUBSET_CFF
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index e9f603dd1d..cc9cb7a1a2 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -172,12 +172,15 @@ struct hb_subset_plan_t
add_table (hb_tag_t tag,
hb_blob_t *contents)
{
- hb_blob_t *source_blob = source->reference_table (tag);
- DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
- HB_UNTAG(tag),
- hb_blob_get_length (contents),
- hb_blob_get_length (source_blob));
- hb_blob_destroy (source_blob);
+ if (HB_DEBUG_SUBSET)
+ {
+ hb_blob_t *source_blob = source->reference_table (tag);
+ DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
+ HB_UNTAG(tag),
+ hb_blob_get_length (contents),
+ hb_blob_get_length (source_blob));
+ hb_blob_destroy (source_blob);
+ }
return hb_face_builder_add_table (dest, tag, contents);
}
};
diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc
index d7f6a6e130..7470bb1b6e 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.cc
+++ b/thirdparty/harfbuzz/src/hb-unicode.cc
@@ -276,7 +276,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
* @ufuncs: The Unicode-functions structure
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified Unicode-functions structure.
@@ -340,7 +340,7 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
* Tests whether the specified Unicode-functions structure
* is immutable.
*
- * Return value: %true if @ufuncs is immutable, false otherwise
+ * Return value: %true if @ufuncs is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -421,7 +421,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
* Calls the composition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @a and @b composed, false otherwise
+ * Return value: %true if @a and @b composed, %false otherwise
*
* Since: 0.9.2
**/
@@ -446,7 +446,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
* Calls the decomposition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @ab was decomposed, false otherwise
+ * Return value: %true if @ab was decomposed, %false otherwise
*
* Since: 0.9.2
**/
@@ -469,7 +469,7 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
* Fetches the compatibility decomposition of a Unicode
* code point. Deprecated.
*
- * Return value:
+ * Return value: length of @decomposed.
*
* Since: 0.9.2
* Deprecated: 2.0.0
diff --git a/thirdparty/harfbuzz/src/hb-unicode.h b/thirdparty/harfbuzz/src/hb-unicode.h
index 7ea0848c0f..c04ee15a09 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.h
+++ b/thirdparty/harfbuzz/src/hb-unicode.h
@@ -28,7 +28,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -41,7 +41,9 @@ HB_BEGIN_DECLS
/**
- * HB_UNICODE_MAX
+ * HB_UNICODE_MAX:
+ *
+ * Maximum valid Unicode code point.
*
* Since: 1.9.0
**/
@@ -427,7 +429,7 @@ typedef hb_script_t (*hb_unicode_script_func_t) (hb_unicode_funcs_t *ufuncs,
* The method must return an #hb_bool_t indicating the success
* of the composition.
*
- * Return value: True is @a,@b composed, false otherwise
+ * Return value: %true is @a,@b composed, %false otherwise
*
**/
typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -451,7 +453,7 @@ typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
* output parameters (if successful). The method must return an
* #hb_bool_t indicating the success of the composition.
*
- * Return value: True if @ab decomposed, false otherwise
+ * Return value: %true if @ab decomposed, %false otherwise
*
**/
typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -467,7 +469,7 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_combining_class_func_t.
*
@@ -483,7 +485,7 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_general_category_func_t.
*
@@ -499,7 +501,7 @@ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_mirroring_func_t.
*
@@ -515,7 +517,7 @@ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_script_func_t.
*
@@ -531,7 +533,7 @@ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_compose_func_t.
*
@@ -547,7 +549,7 @@ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_decompose_func_t.
*
@@ -624,40 +626,12 @@ HB_EXTERN hb_script_t
hb_unicode_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
-/**
- * hb_unicode_compose:
- * @ufuncs: The Unicode-functions structure
- * @a: The first code point to compose
- * @b: The second code point to compose
- * @ab: (out): The composed code point
- *
- * Composes the code point sequence @a,@b by canonical equivalence into
- * code point @ab.
- *
- * Return value: True is @a,@b composed, false otherwise
- *
- * Since: 0.9.2
- **/
HB_EXTERN hb_bool_t
hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab);
-/**
- * hb_unicode_decompose:
- * @ufuncs: The Unicode-functions structure
- * @ab: The code point to decompose
- * @a: (out): The first decomposed code point
- * @b: (out): The second decomposed code point
- *
- * Decomposes code point @ab by canonical equivalence, into code points
- * @a and @b.
- *
- * Return value: True if @ab decomposed, false otherwise
- *
- * Since: 0.9.2
- **/
HB_EXTERN hb_bool_t
hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t ab,
diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh
index 079b94a6b4..13517a9c29 100644
--- a/thirdparty/harfbuzz/src/hb-vector.hh
+++ b/thirdparty/harfbuzz/src/hb-vector.hh
@@ -80,7 +80,12 @@ struct hb_vector_t
fini ();
}
- void reset () { resize (0); }
+ void reset ()
+ {
+ if (unlikely (in_error ()))
+ allocated = length; // Big hack!
+ resize (0);
+ }
hb_vector_t& operator = (const hb_vector_t &o)
{
@@ -181,7 +186,7 @@ struct hb_vector_t
/* Allocate for size but don't adjust length. */
bool alloc (unsigned int size)
{
- if (unlikely (allocated < 0))
+ if (unlikely (in_error ()))
return false;
if (likely (size <= (unsigned) allocated))
@@ -195,7 +200,7 @@ struct hb_vector_t
Type *new_array = nullptr;
bool overflows =
- (int) new_allocated < 0 ||
+ (int) in_error () ||
(new_allocated < (unsigned) allocated) ||
hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index da377b9df6..6db58c3f7c 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,12 +36,41 @@
HB_BEGIN_DECLS
+/**
+ * HB_VERSION_MAJOR:
+ *
+ * The major component of the library version available at compile-time.
+ */
#define HB_VERSION_MAJOR 2
-#define HB_VERSION_MINOR 7
-#define HB_VERSION_MICRO 4
+/**
+ * HB_VERSION_MINOR:
+ *
+ * The minor component of the library version available at compile-time.
+ */
+#define HB_VERSION_MINOR 8
+/**
+ * HB_VERSION_MICRO:
+ *
+ * The micro component of the library version available at compile-time.
+ */
+#define HB_VERSION_MICRO 0
-#define HB_VERSION_STRING "2.7.4"
+/**
+ * HB_VERSION_STRING:
+ *
+ * A string literal containing the library version available at compile-time.
+ */
+#define HB_VERSION_STRING "2.8.0"
+/**
+ * HB_VERSION_ATLEAST:
+ * @major: the major component of the version number
+ * @minor: the minor component of the version number
+ * @micro: the micro component of the version number
+ *
+ * Tests the library version at compile-time against a minimum value,
+ * as three integer components.
+ */
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh
index 274a0e98db..18516581c7 100644
--- a/thirdparty/harfbuzz/src/hb.hh
+++ b/thirdparty/harfbuzz/src/hb.hh
@@ -62,7 +62,6 @@
/* Error. Should never happen. */
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
-#pragma GCC diagnostic error "-Wc++11-narrowing"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
@@ -75,6 +74,7 @@
#pragma GCC diagnostic error "-Wmissing-braces"
#pragma GCC diagnostic error "-Wmissing-declarations"
#pragma GCC diagnostic error "-Wmissing-prototypes"
+#pragma GCC diagnostic error "-Wnarrowing"
#pragma GCC diagnostic error "-Wnested-externs"
#pragma GCC diagnostic error "-Wold-style-definition"
#pragma GCC diagnostic error "-Wpointer-arith"
@@ -126,6 +126,7 @@
#pragma GCC diagnostic ignored "-Wformat-zero-length"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
+#pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it
@@ -175,15 +176,15 @@
#include "hb-aat.h"
#define HB_AAT_H_IN
-#include <limits.h>
-#include <math.h>
-#include <float.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdarg.h>
+#include <cassert>
+#include <cfloat>
+#include <climits>
+#include <cmath>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
#ifdef __MINGW32_VERSION
@@ -244,12 +245,8 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
-#define HB_PURE_FUNC __attribute__((pure))
-#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
-#define HB_PURE_FUNC
-#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
@@ -394,7 +391,7 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#ifndef HB_NO_ERRNO
-# include <errno.h>
+# include <cerrno>
#else
static int HB_UNUSED _hb_errno = 0;
# undef errno
@@ -440,181 +437,12 @@ static int HB_UNUSED _hb_errno = 0;
#define HB_STMT_START do
#define HB_STMT_END while (0)
-/* Static-assert as expression. */
-template <unsigned int cond> class hb_assert_constant_t;
-template <> class hb_assert_constant_t<1> {};
-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
-
/* Lets assert int types. Saves trouble down the road. */
-static_assert ((sizeof (int8_t) == 1), "");
-static_assert ((sizeof (uint8_t) == 1), "");
-static_assert ((sizeof (int16_t) == 2), "");
-static_assert ((sizeof (uint16_t) == 2), "");
-static_assert ((sizeof (int32_t) == 4), "");
-static_assert ((sizeof (uint32_t) == 4), "");
-static_assert ((sizeof (int64_t) == 8), "");
-static_assert ((sizeof (uint64_t) == 8), "");
static_assert ((sizeof (hb_codepoint_t) == 4), "");
static_assert ((sizeof (hb_position_t) == 4), "");
static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
-#define HB_DELETE_COPY_ASSIGN(TypeName) \
- TypeName(const TypeName&) = delete; \
- void operator=(const TypeName&) = delete
-#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
- TypeName() = delete; \
- TypeName(const TypeName&) = delete; \
- void operator=(const TypeName&) = delete
-
-
-/* Flags */
-
-/* Enable bitwise ops on enums marked as flags_t */
-/* To my surprise, looks like the function resolver is happy to silently cast
- * one enum to another... So this doesn't provide the type-checking that I
- * originally had in mind... :(.
- *
- * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
- */
-#ifdef _MSC_VER
-# pragma warning(disable:4200)
-# pragma warning(disable:4800)
-#endif
-#define HB_MARK_AS_FLAG_T(T) \
- extern "C++" { \
- static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
- static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
- static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
- static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
- static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
- static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
- static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
- } \
- static_assert (true, "")
-
-/* Useful for set-operations on small enums.
- * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
- */
-#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
-#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
-#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
-#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
-#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
-
-
-/* Size signifying variable-sized array */
-#ifndef HB_VAR_ARRAY
-#define HB_VAR_ARRAY 1
-#endif
-
-static inline float
-_hb_roundf (float x) { return floorf (x + .5f); }
-#define roundf(x) _hb_roundf(x)
-
-/* Endian swap, used in Windows related backends */
-static inline uint16_t hb_uint16_swap (const uint16_t v)
-{ return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
-
-/*
- * Big-endian integers. Here because fundamental.
- */
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
- public:
- BEInt<Type, 1>& operator = (Type V)
- {
- v = V;
- return *this;
- }
- operator Type () const { return v; }
- private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
- public:
- BEInt<Type, 2>& operator = (Type V)
- {
- v[0] = (V >> 8) & 0xFF;
- v[1] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
- struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- return __builtin_bswap16 (((packed_uint16_t *) this)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
- return ((packed_uint16_t *) this)->v;
-#endif
-#endif
- return (v[0] << 8)
- + (v[1] );
- }
- private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
- public:
- BEInt<Type, 3>& operator = (Type V)
- {
- v[0] = (V >> 16) & 0xFF;
- v[1] = (V >> 8) & 0xFF;
- v[2] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
- return (v[0] << 16)
- + (v[1] << 8)
- + (v[2] );
- }
- private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
- public:
- BEInt<Type, 4>& operator = (Type V)
- {
- v[0] = (V >> 24) & 0xFF;
- v[1] = (V >> 16) & 0xFF;
- v[2] = (V >> 8) & 0xFF;
- v[3] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
- return (v[0] << 24)
- + (v[1] << 16)
- + (v[2] << 8)
- + (v[3] );
- }
- private: uint8_t v[4];
-};
-
-
-/*
- * For lack of a better place, put Zawgyi script hack here.
- * https://github.com/harfbuzz/harfbuzz/issues/1162
- */
-
-#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
-
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
diff --git a/thirdparty/mbedtls/include/mbedtls/config.h b/thirdparty/mbedtls/include/mbedtls/config.h
index e17bc7e306..610f5d1f50 100644
--- a/thirdparty/mbedtls/include/mbedtls/config.h
+++ b/thirdparty/mbedtls/include/mbedtls/config.h
@@ -1747,6 +1747,23 @@
//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT
/**
+ * \def MBEDTLS_TEST_HOOKS
+ *
+ * Enable features for invasive testing such as introspection functions and
+ * hooks for fault injection. This enables additional unit tests.
+ *
+ * Merely enabling this feature should not change the behavior of the product.
+ * It only adds new code, and new branching points where the default behavior
+ * is the same as when this feature is disabled.
+ * However, this feature increases the attack surface: there is an added
+ * risk of vulnerabilities, and more gadgets that can make exploits easier.
+ * Therefore this feature must never be enabled in production.
+ *
+ * Uncomment to enable invasive tests.
+ */
+//#define MBEDTLS_TEST_HOOKS
+
+/**
* \def MBEDTLS_THREADING_ALT
*
* Provide your own alternate threading implementation.
diff --git a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
index 278fbbbb7a..6c099adf4d 100644
--- a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
@@ -214,6 +214,13 @@ typedef struct mbedtls_ctr_drbg_context
void *p_entropy; /*!< The context for the entropy function. */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized if and only if f_entropy != NULL.
+ * This means that the mutex is initialized during the initial seeding
+ * in mbedtls_ctr_drbg_seed() and freed in mbedtls_ctr_drbg_free().
+ *
+ * Note that this invariant may change without notice. Do not rely on it
+ * and do not access the mutex directly in application code.
+ */
mbedtls_threading_mutex_t mutex;
#endif
}
@@ -277,6 +284,15 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
* device.
*/
#endif
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
/**
* \param ctx The CTR_DRBG context to seed.
* It must have been initialized with
@@ -286,6 +302,8 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
* the same context unless you call
* mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
* again first.
+ * After a failed call to mbedtls_ctr_drbg_seed(),
+ * you must call mbedtls_ctr_drbg_free().
* \param f_entropy The entropy callback, taking as arguments the
* \p p_entropy context, the buffer to fill, and the
* length of the buffer.
@@ -377,6 +395,11 @@ void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
* \brief This function reseeds the CTR_DRBG context, that is
* extracts data from the entropy source.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The CTR_DRBG context.
* \param additional Additional data to add to the state. Can be \c NULL.
* \param len The length of the additional data.
@@ -394,6 +417,11 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
/**
* \brief This function updates the state of the CTR_DRBG context.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The CTR_DRBG context.
* \param additional The data to update the state with. This must not be
* \c NULL unless \p add_len is \c 0.
@@ -417,6 +445,11 @@ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
@@ -445,8 +478,16 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng,
*
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
- *
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
diff --git a/thirdparty/mbedtls/include/mbedtls/entropy.h b/thirdparty/mbedtls/include/mbedtls/entropy.h
index 1e1d3f56ec..1d6e9b821b 100644
--- a/thirdparty/mbedtls/include/mbedtls/entropy.h
+++ b/thirdparty/mbedtls/include/mbedtls/entropy.h
@@ -147,13 +147,15 @@ mbedtls_entropy_source_state;
*/
typedef struct mbedtls_entropy_context
{
- int accumulator_started;
+ int accumulator_started; /* 0 after init.
+ * 1 after the first update.
+ * -1 after free. */
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
mbedtls_sha512_context accumulator;
#else
mbedtls_sha256_context accumulator;
#endif
- int source_count;
+ int source_count; /* Number of entries used in source. */
mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES];
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_state havege_data;
diff --git a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
index 970c033c15..5718e187a9 100644
--- a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
@@ -128,6 +128,14 @@ typedef struct mbedtls_hmac_drbg_context
void *p_entropy; /*!< context for the entropy function */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized if and only if
+ * md_ctx->md_info != NULL. This means that the mutex is initialized
+ * during the initial seeding in mbedtls_hmac_drbg_seed() or
+ * mbedtls_hmac_drbg_seed_buf() and freed in mbedtls_ctr_drbg_free().
+ *
+ * Note that this invariant may change without notice. Do not rely on it
+ * and do not access the mutex directly in application code.
+ */
mbedtls_threading_mutex_t mutex;
#endif
} mbedtls_hmac_drbg_context;
@@ -177,7 +185,17 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx );
* \note During the initial seeding, this function calls
* the entropy source to obtain a nonce
* whose length is half the entropy length.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_hmac_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param ctx HMAC_DRBG context to be seeded.
* \param md_info MD algorithm to use for HMAC_DRBG.
* \param f_entropy The entropy callback, taking as arguments the
@@ -216,7 +234,17 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
*
* This function is meant for use in algorithms that need a pseudorandom
* input such as deterministic ECDSA.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_hmac_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param ctx HMAC_DRBG context to be initialised.
* \param md_info MD algorithm to use for HMAC_DRBG.
* \param data Concatenation of the initial entropy string and
@@ -279,6 +307,11 @@ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx,
/**
* \brief This function updates the state of the HMAC_DRBG context.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The HMAC_DRBG context.
* \param additional The data to update the state with.
* If this is \c NULL, there is no additional data.
@@ -295,6 +328,11 @@ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
* \brief This function reseeds the HMAC_DRBG context, that is
* extracts data from the entropy source.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The HMAC_DRBG context.
* \param additional Additional data to add to the state.
* If this is \c NULL, there is no additional data
@@ -320,6 +358,11 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param p_rng The HMAC_DRBG context. This must be a pointer to a
* #mbedtls_hmac_drbg_context structure.
* \param output The buffer to fill.
@@ -349,7 +392,16 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng,
*
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param p_rng The HMAC_DRBG context. This must be a pointer to a
* #mbedtls_hmac_drbg_context structure.
* \param output The buffer to fill.
diff --git a/thirdparty/mbedtls/include/mbedtls/net_sockets.h b/thirdparty/mbedtls/include/mbedtls/net_sockets.h
index 00fea7db19..c6e1a0270e 100644
--- a/thirdparty/mbedtls/include/mbedtls/net_sockets.h
+++ b/thirdparty/mbedtls/include/mbedtls/net_sockets.h
@@ -151,6 +151,7 @@ int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char
*
* \return 0 if successful, or one of:
* MBEDTLS_ERR_NET_SOCKET_FAILED,
+ * MBEDTLS_ERR_NET_UNKNOWN_HOST,
* MBEDTLS_ERR_NET_BIND_FAILED,
* MBEDTLS_ERR_NET_LISTEN_FAILED
*
@@ -170,6 +171,8 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
* can be NULL if client_ip is null
*
* \return 0 if successful, or
+ * MBEDTLS_ERR_NET_SOCKET_FAILED,
+ * MBEDTLS_ERR_NET_BIND_FAILED,
* MBEDTLS_ERR_NET_ACCEPT_FAILED, or
* MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small,
* MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to
@@ -182,6 +185,10 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
/**
* \brief Check and wait for the context to be ready for read/write
*
+ * \note The current implementation of this function uses
+ * select() and returns an error if the file descriptor
+ * is \c FD_SETSIZE or greater.
+ *
* \param ctx Socket to check
* \param rw Bitflag composed of MBEDTLS_NET_POLL_READ and
* MBEDTLS_NET_POLL_WRITE specifying the events
@@ -263,16 +270,21 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len );
* 'timeout' seconds. If no error occurs, the actual amount
* read is returned.
*
+ * \note The current implementation of this function uses
+ * select() and returns an error if the file descriptor
+ * is \c FD_SETSIZE or greater.
+ *
* \param ctx Socket
* \param buf The buffer to write to
* \param len Maximum length of the buffer
* \param timeout Maximum number of milliseconds to wait for data
* 0 means no timeout (wait forever)
*
- * \return the number of bytes received,
- * or a non-zero error code:
- * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out,
+ * \return The number of bytes received if successful.
+ * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out.
* MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal.
+ * Another negative error code (MBEDTLS_ERR_NET_xxx)
+ * for other failures.
*
* \note This function will block (until data becomes available or
* timeout is reached) even if the socket is set to
diff --git a/thirdparty/mbedtls/include/mbedtls/rsa.h b/thirdparty/mbedtls/include/mbedtls/rsa.h
index 188c37cf3a..b2f65334fe 100644
--- a/thirdparty/mbedtls/include/mbedtls/rsa.h
+++ b/thirdparty/mbedtls/include/mbedtls/rsa.h
@@ -124,7 +124,10 @@ extern "C" {
*/
typedef struct mbedtls_rsa_context
{
- int ver; /*!< Always 0.*/
+ int ver; /*!< Reserved for internal purposes.
+ * Do not set this field in application
+ * code. Its meaning might change without
+ * notice. */
size_t len; /*!< The size of \p N in Bytes. */
mbedtls_mpi N; /*!< The public modulus. */
@@ -154,6 +157,7 @@ typedef struct mbedtls_rsa_context
mask generating function used in the
EME-OAEP and EMSA-PSS encodings. */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized iff ver != 0. */
mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex. */
#endif
}
diff --git a/thirdparty/mbedtls/include/mbedtls/threading.h b/thirdparty/mbedtls/include/mbedtls/threading.h
index a8183a6ef4..45161ce467 100644
--- a/thirdparty/mbedtls/include/mbedtls/threading.h
+++ b/thirdparty/mbedtls/include/mbedtls/threading.h
@@ -73,6 +73,9 @@ extern "C" {
typedef struct mbedtls_threading_mutex_t
{
pthread_mutex_t mutex;
+ /* is_valid is 0 after a failed init or a free, and nonzero after a
+ * successful init. This field is not considered part of the public
+ * API of Mbed TLS and may change without notice. */
char is_valid;
} mbedtls_threading_mutex_t;
#endif
diff --git a/thirdparty/mbedtls/include/mbedtls/version.h b/thirdparty/mbedtls/include/mbedtls/version.h
index 5f0a8f114c..bd5c730c1d 100644
--- a/thirdparty/mbedtls/include/mbedtls/version.h
+++ b/thirdparty/mbedtls/include/mbedtls/version.h
@@ -65,16 +65,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 16
-#define MBEDTLS_VERSION_PATCH 9
+#define MBEDTLS_VERSION_PATCH 10
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x02100900
-#define MBEDTLS_VERSION_STRING "2.16.9"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.9"
+#define MBEDTLS_VERSION_NUMBER 0x02100A00
+#define MBEDTLS_VERSION_STRING "2.16.10"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.10"
#if defined(MBEDTLS_VERSION_C)
diff --git a/thirdparty/mbedtls/library/base64.c b/thirdparty/mbedtls/library/base64.c
index bfafb05353..692e11e3fa 100644
--- a/thirdparty/mbedtls/library/base64.c
+++ b/thirdparty/mbedtls/library/base64.c
@@ -97,6 +97,99 @@ static const unsigned char base64_dec_map[128] =
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
+ * Constant flow conditional assignment to unsigned char
+ */
+static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src,
+ unsigned char condition )
+{
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ /* Generate bitmask from condition, mask will either be 0xFF or 0 */
+ unsigned char mask = ( condition | -condition );
+ mask >>= 7;
+ mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow conditional assignment to uint_32
+ */
+static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src,
+ uint32_t condition )
+{
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
+ uint32_t mask = ( condition | -condition );
+ mask >>= 31;
+ mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ *dest = ( src & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow check for equality
+ */
+static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b )
+{
+ size_t difference = in_a ^ in_b;
+
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ difference |= -difference;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ /* cope with the varying size of size_t per platform */
+ difference >>= ( sizeof( difference ) * 8 - 1 );
+
+ return (unsigned char) ( 1 ^ difference );
+}
+
+/*
+ * Constant flow lookup into table.
+ */
+static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table,
+ const size_t table_size, const size_t table_index )
+{
+ size_t i;
+ unsigned char result = 0;
+
+ for( i = 0; i < table_size; ++i )
+ {
+ mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) );
+ }
+
+ return result;
+}
+
+/*
* Encode a buffer into base64 format
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
@@ -136,10 +229,17 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
C2 = *src++;
C3 = *src++;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
- *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
- *p++ = base64_enc_map[C3 & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( C1 >> 2 ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( C3 & 0x3F ) );
}
if( i < slen )
@@ -147,11 +247,15 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
C1 = *src++;
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( C1 >> 2 ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
if( ( i + 1 ) < slen )
- *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
else *p++ = '=';
*p++ = '=';
@@ -172,6 +276,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
size_t i, n;
uint32_t j, x;
unsigned char *p;
+ unsigned char dec_map_lookup;
/* First pass: check for validity and get output length */
for( i = n = j = 0; i < slen; i++ )
@@ -202,10 +307,12 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
if( src[i] == '=' && ++j > 2 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
- if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+ dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
+
+ if( src[i] > 127 || dec_map_lookup == 127 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
- if( base64_dec_map[src[i]] < 64 && j != 0 )
+ if( dec_map_lookup < 64 && j != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
n++;
@@ -235,8 +342,10 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
if( *src == '\r' || *src == '\n' || *src == ' ' )
continue;
- j -= ( base64_dec_map[*src] == 64 );
- x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
+ dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src );
+
+ mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) );
+ x = ( x << 6 ) | ( dec_map_lookup & 0x3F );
if( ++n == 4 )
{
diff --git a/thirdparty/mbedtls/library/bignum.c b/thirdparty/mbedtls/library/bignum.c
index 2feb727d89..f133f6c13c 100644
--- a/thirdparty/mbedtls/library/bignum.c
+++ b/thirdparty/mbedtls/library/bignum.c
@@ -1354,6 +1354,12 @@ int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
for( n = B->n; n > 0; n-- )
if( B->p[n - 1] != 0 )
break;
+ if( n > A->n )
+ {
+ /* B >= (2^ciL)^n > A */
+ ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
+ goto cleanup;
+ }
carry = mpi_sub_hlp( n, X->p, B->p );
if( carry != 0 )
diff --git a/thirdparty/mbedtls/library/ctr_drbg.c b/thirdparty/mbedtls/library/ctr_drbg.c
index e92008bbe8..90264e844a 100644
--- a/thirdparty/mbedtls/library/ctr_drbg.c
+++ b/thirdparty/mbedtls/library/ctr_drbg.c
@@ -83,10 +83,6 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
/*
@@ -99,14 +95,13 @@ void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
return;
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* The mutex is initialized iff f_entropy is set. */
+ if( ctx->f_entropy != NULL )
+ mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_aes_free( &ctx->aes_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
@@ -422,6 +417,11 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
+ /* The mutex is initialized iff f_entropy is set. */
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
mbedtls_aes_init( &ctx->aes_ctx );
ctx->f_entropy = f_entropy;
diff --git a/thirdparty/mbedtls/library/ecdsa.c b/thirdparty/mbedtls/library/ecdsa.c
index da8df9cde2..2456238b17 100644
--- a/thirdparty/mbedtls/library/ecdsa.c
+++ b/thirdparty/mbedtls/library/ecdsa.c
@@ -247,6 +247,9 @@ static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx )
#endif /* MBEDTLS_ECP_RESTARTABLE */
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC) || \
+ !defined(MBEDTLS_ECDSA_SIGN_ALT) || \
+ !defined(MBEDTLS_ECDSA_VERIFY_ALT)
/*
* Derive a suitable integer for group grp from a buffer of length len
* SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
@@ -269,6 +272,7 @@ static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x,
cleanup:
return( ret );
}
+#endif /* ECDSA_DETERMINISTIC || !ECDSA_SIGN_ALT || !ECDSA_VERIFY_ALT */
#if !defined(MBEDTLS_ECDSA_SIGN_ALT)
/*
@@ -780,6 +784,8 @@ int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
(void) md_alg;
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
+ (void) rs_ctx;
+
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng ) );
#else
@@ -888,6 +894,8 @@ int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
goto cleanup;
}
#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
+ (void) rs_ctx;
+
if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
&ctx->Q, &r, &s ) ) != 0 )
goto cleanup;
diff --git a/thirdparty/mbedtls/library/ecjpake.c b/thirdparty/mbedtls/library/ecjpake.c
index f6e24580c7..0532a295e6 100644
--- a/thirdparty/mbedtls/library/ecjpake.c
+++ b/thirdparty/mbedtls/library/ecjpake.c
@@ -850,6 +850,8 @@ static const unsigned char ecjpake_test_password[] = {
0x65, 0x73, 0x74
};
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+
static const unsigned char ecjpake_test_x1[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
@@ -994,6 +996,8 @@ cleanup:
return( ret );
}
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
+
/* For tests we don't need a secure RNG;
* use the LGC from Numerical Recipes for simplicity */
static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
@@ -1089,6 +1093,12 @@ int mbedtls_ecjpake_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "passed\n" );
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+ /* 'reference handshake' tests can only be run against implementations
+ * for which we have 100% control over how the random ephemeral keys
+ * are generated. This is only the case for the internal mbed TLS
+ * implementation, so these tests are skipped in case the internal
+ * implementation is swapped out for an alternative one. */
if( verbose != 0 )
mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
@@ -1137,6 +1147,7 @@ int mbedtls_ecjpake_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "passed\n" );
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
cleanup:
mbedtls_ecjpake_free( &cli );
diff --git a/thirdparty/mbedtls/library/entropy.c b/thirdparty/mbedtls/library/entropy.c
index 666c55654c..c5f414a010 100644
--- a/thirdparty/mbedtls/library/entropy.c
+++ b/thirdparty/mbedtls/library/entropy.c
@@ -146,6 +146,11 @@ void mbedtls_entropy_init( mbedtls_entropy_context *ctx )
void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
{
+ /* If the context was already free, don't call free() again.
+ * This is important for mutexes which don't allow double-free. */
+ if( ctx->accumulator_started == -1 )
+ return;
+
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_free( &ctx->havege_data );
#endif
@@ -162,7 +167,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
#endif
ctx->source_count = 0;
mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
- ctx->accumulator_started = 0;
+ ctx->accumulator_started = -1;
}
int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
diff --git a/thirdparty/mbedtls/library/hmac_drbg.c b/thirdparty/mbedtls/library/hmac_drbg.c
index 10cbd462ba..b45d61616f 100644
--- a/thirdparty/mbedtls/library/hmac_drbg.c
+++ b/thirdparty/mbedtls/library/hmac_drbg.c
@@ -84,10 +84,6 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
/*
@@ -159,6 +155,10 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
/*
* Set initial working state.
* Use the V memory location, which is currently all 0, to initialize the
@@ -284,6 +284,11 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
+ /* The mutex is initialized iff the md context is set up. */
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
md_size = mbedtls_md_get_size( md_info );
/*
@@ -451,14 +456,13 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
return;
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* The mutex is initialized iff the md context is set up. */
+ if( ctx->md_ctx.md_info != NULL )
+ mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_md_free( &ctx->md_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
#if defined(MBEDTLS_FS_IO)
diff --git a/thirdparty/mbedtls/library/net_sockets.c b/thirdparty/mbedtls/library/net_sockets.c
index 1130408263..671115f15f 100644
--- a/thirdparty/mbedtls/library/net_sockets.c
+++ b/thirdparty/mbedtls/library/net_sockets.c
@@ -496,6 +496,13 @@ int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout )
if( fd < 0 )
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
+ /* A limitation of select() is that it only works with file descriptors
+ * that are strictly less than FD_SETSIZE. This is a limitation of the
+ * fd_set type. Error out early, because attempting to call FD_SET on a
+ * large file descriptor is a buffer overflow on typical platforms. */
+ if( fd >= FD_SETSIZE )
+ return( MBEDTLS_ERR_NET_POLL_FAILED );
+
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
/* Ensure that memory sanitizers consider read_fds and write_fds as
@@ -615,6 +622,13 @@ int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf,
if( fd < 0 )
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
+ /* A limitation of select() is that it only works with file descriptors
+ * that are strictly less than FD_SETSIZE. This is a limitation of the
+ * fd_set type. Error out early, because attempting to call FD_SET on a
+ * large file descriptor is a buffer overflow on typical platforms. */
+ if( fd >= FD_SETSIZE )
+ return( MBEDTLS_ERR_NET_POLL_FAILED );
+
FD_ZERO( &read_fds );
FD_SET( fd, &read_fds );
diff --git a/thirdparty/mbedtls/library/pkwrite.c b/thirdparty/mbedtls/library/pkwrite.c
index 150626c147..a770dfb93e 100644
--- a/thirdparty/mbedtls/library/pkwrite.c
+++ b/thirdparty/mbedtls/library/pkwrite.c
@@ -455,7 +455,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1
* }
*/
-#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE
+#define RSA_PUB_DER_MAX_BYTES ( 38 + 2 * MBEDTLS_MPI_MAX_SIZE )
/*
* RSA private keys:
@@ -472,10 +472,10 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported)
* }
*/
-#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \
- MBEDTLS_MPI_MAX_SIZE % 2
-#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
- + 5 * MPI_MAX_SIZE_2
+#define MPI_MAX_SIZE_2 ( MBEDTLS_MPI_MAX_SIZE / 2 + \
+ MBEDTLS_MPI_MAX_SIZE % 2 )
+#define RSA_PRV_DER_MAX_BYTES ( 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
+ + 5 * MPI_MAX_SIZE_2 )
#else /* MBEDTLS_RSA_C */
@@ -496,7 +496,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* + 2 * ECP_MAX (coords) [1]
* }
*/
-#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PUB_DER_MAX_BYTES ( 30 + 2 * MBEDTLS_ECP_MAX_BYTES )
/*
* EC private keys:
@@ -507,7 +507,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above
* }
*/
-#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PRV_DER_MAX_BYTES ( 29 + 3 * MBEDTLS_ECP_MAX_BYTES )
#else /* MBEDTLS_ECP_C */
@@ -516,10 +516,10 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
#endif /* MBEDTLS_ECP_C */
-#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
- RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES
-#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
- RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES
+#define PUB_DER_MAX_BYTES ( RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES )
+#define PRV_DER_MAX_BYTES ( RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
+ RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES )
int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
diff --git a/thirdparty/mbedtls/library/rsa.c b/thirdparty/mbedtls/library/rsa.c
index a25c633bc6..c8c23dba8c 100644
--- a/thirdparty/mbedtls/library/rsa.c
+++ b/thirdparty/mbedtls/library/rsa.c
@@ -520,6 +520,9 @@ void mbedtls_rsa_init( mbedtls_rsa_context *ctx,
mbedtls_rsa_set_padding( ctx, padding, hash_id );
#if defined(MBEDTLS_THREADING_C)
+ /* Set ctx->ver to nonzero to indicate that the mutex has been
+ * initialized and will need to be freed. */
+ ctx->ver = 1;
mbedtls_mutex_init( &ctx->mutex );
#endif
}
@@ -567,9 +570,6 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
RSA_VALIDATE_RET( ctx != NULL );
RSA_VALIDATE_RET( f_rng != NULL );
- if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
- return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
/*
* If the modulus is 1024 bit long or shorter, then the security strength of
* the RSA algorithm is less than or equal to 80 bits and therefore an error
@@ -582,6 +582,12 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
mbedtls_mpi_init( &G );
mbedtls_mpi_init( &L );
+ if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
/*
* find primes P and Q with Q < P so that:
* 1. |P-Q| > 2^( nbits / 2 - 100 )
@@ -659,7 +665,9 @@ cleanup:
if( ret != 0 )
{
mbedtls_rsa_free( ctx );
- return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
+ if( ( -ret & ~0x7f ) == 0 )
+ ret = MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret;
+ return( ret );
}
return( 0 );
@@ -1106,10 +1114,10 @@ cleanup:
mbedtls_mpi_free( &C );
mbedtls_mpi_free( &I );
- if( ret != 0 )
+ if( ret != 0 && ret >= -0x007f )
return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
- return( 0 );
+ return( ret );
}
#if defined(MBEDTLS_PKCS1_V21)
@@ -2502,7 +2510,6 @@ int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src )
RSA_VALIDATE_RET( dst != NULL );
RSA_VALIDATE_RET( src != NULL );
- dst->ver = src->ver;
dst->len = src->len;
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
@@ -2561,7 +2568,12 @@ void mbedtls_rsa_free( mbedtls_rsa_context *ctx )
#endif /* MBEDTLS_RSA_NO_CRT */
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* Free the mutex, but only if it hasn't been freed already. */
+ if( ctx->ver != 0 )
+ {
+ mbedtls_mutex_free( &ctx->mutex );
+ ctx->ver = 0;
+ }
#endif
}
diff --git a/thirdparty/mbedtls/library/threading.c b/thirdparty/mbedtls/library/threading.c
index f4f29cff5e..0dc5488c1a 100644
--- a/thirdparty/mbedtls/library/threading.c
+++ b/thirdparty/mbedtls/library/threading.c
@@ -98,6 +98,12 @@ static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
if( mutex == NULL )
return;
+ /* A nonzero value of is_valid indicates a successfully initialized
+ * mutex. This is a workaround for not being able to return an error
+ * code for this function. The lock/unlock functions return an error
+ * if is_valid is nonzero. The Mbed TLS unit test code uses this field
+ * to distinguish more states of the mutex; see helpers.function for
+ * details. */
mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0;
}
diff --git a/thirdparty/mbedtls/library/version_features.c b/thirdparty/mbedtls/library/version_features.c
index cbf38dc2c2..8c8e815e9d 100644
--- a/thirdparty/mbedtls/library/version_features.c
+++ b/thirdparty/mbedtls/library/version_features.c
@@ -553,6 +553,9 @@ static const char *features[] = {
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT)
"MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT",
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */
+#if defined(MBEDTLS_TEST_HOOKS)
+ "MBEDTLS_TEST_HOOKS",
+#endif /* MBEDTLS_TEST_HOOKS */
#if defined(MBEDTLS_THREADING_ALT)
"MBEDTLS_THREADING_ALT",
#endif /* MBEDTLS_THREADING_ALT */
diff --git a/thirdparty/miniupnpc/LICENSE b/thirdparty/miniupnpc/LICENSE
index 1460310752..6ddd381baa 100644
--- a/thirdparty/miniupnpc/LICENSE
+++ b/thirdparty/miniupnpc/LICENSE
@@ -1,5 +1,5 @@
-MiniUPnP Project
-Copyright (c) 2005-2019, Thomas BERNARD
+MiniUPnPc
+Copyright (c) 2005-2020, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -24,3 +24,4 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c
new file mode 100644
index 0000000000..7e586d7da2
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c
@@ -0,0 +1,79 @@
+/* $Id: addr_is_reserved.c,v 1.4 2021/03/02 23:40:32 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project : miniupnp
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2021 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#ifdef _WIN32
+/* Win32 Specific includes and defines */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#if !defined(_MSC_VER)
+#include <stdint.h>
+#else /* !defined(_MSC_VER) */
+typedef unsigned long uint32_t;
+#endif /* !defined(_MSC_VER) */
+#else /* _WIN32 */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* _WIN32 */
+
+/* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */
+#define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+#define MSK(m) (32-(m))
+static const struct { uint32_t address; uint32_t rmask; } reserved[] = {
+ { IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */
+ { IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */
+ { IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */
+ { IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */
+ { IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */
+ { IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */
+ { IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */
+ { IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */
+ { IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */
+ { IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */
+ { IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */
+ { IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */
+ { IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */
+ { IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */
+ { IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */
+ { IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */
+ { IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */
+ { IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */
+};
+#undef IP
+#undef MSK
+
+/**
+ * @return 1 or 0
+ */
+int addr_is_reserved(const char * addr_str)
+{
+ uint32_t addr_n, address;
+ size_t i;
+
+#if defined(_WIN32) && (!defined(_WIN32_WINNT_VISTA) || (_WIN32_WINNT < _WIN32_WINNT_VISTA))
+ addr_n = inet_addr(addr_str);
+ if (addr_n == INADDR_NONE)
+ return 1;
+#else
+ /* was : addr_n = inet_addr(addr_str); */
+ if (inet_pton(AF_INET, addr_str, &addr_n) <= 0) {
+ /* error */
+ return 1;
+ }
+#endif
+
+ address = ntohl(addr_n);
+
+ for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) {
+ if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask))
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h
new file mode 100644
index 0000000000..f8b5d66a09
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h
@@ -0,0 +1,14 @@
+/* $Id: $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project: miniupnp
+ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef ADDR_IS_RESERVED_H_INCLUDED
+#define ADDR_IS_RESERVED_H_INCLUDED
+
+int addr_is_reserved(const char * addr_str);
+
+#endif /* ADDR_IS_RESERVED_H_INCLUDED */
diff --git a/thirdparty/miniupnpc/miniupnpc/connecthostport.c b/thirdparty/miniupnpc/miniupnpc/connecthostport.c
index f3982e1a77..79f832b8db 100644
--- a/thirdparty/miniupnpc/miniupnpc/connecthostport.c
+++ b/thirdparty/miniupnpc/miniupnpc/connecthostport.c
@@ -1,8 +1,8 @@
-/* $Id: connecthostport.c,v 1.22 2019/10/13 17:22:08 nanard Exp $ */
+/* $Id: connecthostport.c,v 1.24 2020/11/09 19:26:53 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
* Author : Thomas Bernard
- * Copyright (c) 2010-2019 Thomas Bernard
+ * Copyright (c) 2010-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -19,7 +19,7 @@
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define herror
#define socklen_t int
#else /* #ifdef _WIN32 */
diff --git a/thirdparty/miniupnpc/miniupnpc/listdevices.c b/thirdparty/miniupnpc/miniupnpc/listdevices.c
deleted file mode 100644
index bd9ba57efc..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/listdevices.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* $Id: listdevices.c,v 1.6 2015/07/23 20:40:08 nanard Exp $ */
-/* Project : miniupnp
- * Author : Thomas Bernard
- * Copyright (c) 2013-2015 Thomas Bernard
- * This software is subject to the conditions detailed in the
- * LICENCE file provided in this distribution. */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#endif /* _WIN32 */
-#include "miniupnpc.h"
-
-struct upnp_dev_list {
- struct upnp_dev_list * next;
- char * descURL;
- struct UPNPDev * * array;
- size_t count;
- size_t allocated_count;
-};
-
-#define ADD_DEVICE_COUNT_STEP 16
-
-void add_device(struct upnp_dev_list * * list_head, struct UPNPDev * dev)
-{
- struct upnp_dev_list * elt;
- size_t i;
-
- if(dev == NULL)
- return;
- for(elt = *list_head; elt != NULL; elt = elt->next) {
- if(strcmp(elt->descURL, dev->descURL) == 0) {
- for(i = 0; i < elt->count; i++) {
- if (strcmp(elt->array[i]->st, dev->st) == 0 && strcmp(elt->array[i]->usn, dev->usn) == 0) {
- return; /* already found */
- }
- }
- if(elt->count >= elt->allocated_count) {
- struct UPNPDev * * tmp;
- elt->allocated_count += ADD_DEVICE_COUNT_STEP;
- tmp = realloc(elt->array, elt->allocated_count * sizeof(struct UPNPDev *));
- if(tmp == NULL) {
- fprintf(stderr, "Failed to realloc(%p, %lu)\n", elt->array, (unsigned long)(elt->allocated_count * sizeof(struct UPNPDev *)));
- return;
- }
- elt->array = tmp;
- }
- elt->array[elt->count++] = dev;
- return;
- }
- }
- elt = malloc(sizeof(struct upnp_dev_list));
- if(elt == NULL) {
- fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)sizeof(struct upnp_dev_list));
- return;
- }
- elt->next = *list_head;
- elt->descURL = strdup(dev->descURL);
- if(elt->descURL == NULL) {
- fprintf(stderr, "Failed to strdup(%s)\n", dev->descURL);
- free(elt);
- return;
- }
- elt->allocated_count = ADD_DEVICE_COUNT_STEP;
- elt->array = malloc(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *));
- if(elt->array == NULL) {
- fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *)));
- free(elt->descURL);
- free(elt);
- return;
- }
- elt->array[0] = dev;
- elt->count = 1;
- *list_head = elt;
-}
-
-void free_device(struct upnp_dev_list * elt)
-{
- free(elt->descURL);
- free(elt->array);
- free(elt);
-}
-
-int main(int argc, char * * argv)
-{
- const char * searched_device = NULL;
- const char * * searched_devices = NULL;
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- int ipv6 = 0;
- unsigned char ttl = 2;
- int error = 0;
- struct UPNPDev * devlist = 0;
- struct UPNPDev * dev;
- struct upnp_dev_list * sorted_list = NULL;
- struct upnp_dev_list * dev_array;
- int i;
-
-#ifdef _WIN32
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if(nResult != NO_ERROR)
- {
- fprintf(stderr, "WSAStartup() failed.\n");
- return -1;
- }
-#endif
-
- for(i = 1; i < argc; i++) {
- if(strcmp(argv[i], "-6") == 0)
- ipv6 = 1;
- else if(strcmp(argv[i], "-d") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "%s option needs one argument\n", "-d");
- return 1;
- }
- searched_device = argv[i];
- } else if(strcmp(argv[i], "-t") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "%s option needs one argument\n", "-t");
- return 1;
- }
- ttl = (unsigned char)atoi(argv[i]);
- } else if(strcmp(argv[i], "-l") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "-l option needs at least one argument\n");
- return 1;
- }
- searched_devices = (const char * *)(argv + i);
- break;
- } else if(strcmp(argv[i], "-m") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "-m option needs one argument\n");
- return 1;
- }
- multicastif = argv[i];
- } else {
- printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
- printf("options :\n");
- printf(" -6 : use IPv6\n");
- printf(" -m address/ifname : network interface to use for multicast\n");
- printf(" -d <device string> : search only for this type of device\n");
- printf(" -l <device1> <device2> ... : search only for theses types of device\n");
- printf(" -t ttl : set multicast TTL. Default value is 2.\n");
- printf(" -h : this help\n");
- return 1;
- }
- }
-
- if(searched_device) {
- printf("searching UPnP device type %s\n", searched_device);
- devlist = upnpDiscoverDevice(searched_device,
- 2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error);
- } else if(searched_devices) {
- printf("searching UPnP device types :\n");
- for(i = 0; searched_devices[i]; i++)
- printf("\t%s\n", searched_devices[i]);
- devlist = upnpDiscoverDevices(searched_devices,
- 2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error, 1);
- } else {
- printf("searching all UPnP devices\n");
- devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error);
- }
- if(devlist) {
- for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
- printf("%3d: %-48s\n", i, dev->st);
- printf(" %s\n", dev->descURL);
- printf(" %s\n", dev->usn);
- add_device(&sorted_list, dev);
- }
- putchar('\n');
- for (dev_array = sorted_list; dev_array != NULL ; dev_array = dev_array->next) {
- printf("%s :\n", dev_array->descURL);
- for(i = 0; (unsigned)i < dev_array->count; i++) {
- printf("%2d: %s\n", i+1, dev_array->array[i]->st);
- printf(" %s\n", dev_array->array[i]->usn);
- }
- putchar('\n');
- }
- freeUPNPDevlist(devlist);
- while(sorted_list != NULL) {
- dev_array = sorted_list;
- sorted_list = sorted_list->next;
- free_device(dev_array);
- }
- } else {
- printf("no device found.\n");
- }
-
- return 0;
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/minisoap.c b/thirdparty/miniupnpc/miniupnpc/minisoap.c
index f92b36ce89..78606672d5 100644
--- a/thirdparty/miniupnpc/miniupnpc/minisoap.c
+++ b/thirdparty/miniupnpc/miniupnpc/minisoap.c
@@ -1,8 +1,8 @@
-/* $Id: minisoap.c,v 1.25 2017/04/21 10:03:24 nanard Exp $ */
+/* $Id: minisoap.c,v 1.30 2020/11/09 19:27:42 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
* Author : Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
*
@@ -13,7 +13,7 @@
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#else
#include <unistd.h>
#include <sys/types.h>
diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
index 36244dedec..0ef7e12cfb 100644
--- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c
+++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
@@ -1,15 +1,15 @@
-/* $Id: minissdpc.c,v 1.40 2019/04/23 12:12:55 nanard Exp $ */
+/* $Id: minissdpc.c,v 1.47 2021/03/02 23:38:30 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2019 Thomas Bernard
+ * copyright (c) 2005-2021 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
-/*#include <syslog.h>*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
#include <sys/types.h>
#if defined (__NetBSD__)
#include <net/if.h>
@@ -20,7 +20,7 @@
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#if !defined(_MSC_VER)
#include <stdint.h>
#else /* !defined(_MSC_VER) */
@@ -33,6 +33,12 @@ typedef unsigned short uint16_t;
#define strncasecmp memicmp
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#endif /* #ifndef strncasecmp */
+#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION)
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
+#define in6addr_any in6addr_any_init
+static const IN6_ADDR in6addr_any_init = {0};
+#endif
+#endif
#endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h>
@@ -66,7 +72,7 @@ struct sockaddr_un {
#define HAS_IP_MREQN
#endif
-#if !defined(HAS_IP_MREQN) && !defined(_WIN32)
+#ifndef _WIN32
#include <sys/ioctl.h>
#if defined(__sun) || defined(__HAIKU__)
#include <sys/sockio.h>
@@ -445,6 +451,36 @@ parseMSEARCHReply(const char * reply, int size,
}
}
+#if defined(CLOCK_MONOTONIC_FAST)
+#define UPNP_CLOCKID CLOCK_MONOTONIC_FAST
+#elif defined(CLOCK_MONOTONIC)
+#define UPNP_CLOCKID CLOCK_MONOTONIC
+#endif
+
+static int upnp_gettimeofday(struct timeval * tv)
+{
+#if defined(_WIN32)
+#if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ ULONGLONG ts = GetTickCount64();
+#else
+ DWORD ts = GetTickCount();
+#endif
+ tv->tv_sec = (long)(ts / 1000);
+ tv->tv_usec = (ts % 1000) * 1000;
+ return 0; /* success */
+#elif defined(CLOCK_MONOTONIC_FAST) || defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ int ret_code = clock_gettime(UPNP_CLOCKID, &ts);
+ if (ret_code == 0)
+ {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ret_code;
+#else
+ return gettimeofday(tv, NULL);
+#endif
+}
/* port upnp discover : SSDP protocol */
#define SSDP_PORT 1900
#define XSTR(s) STR(s)
@@ -540,12 +576,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6) {
DWORD ifbestidx;
- SOCKADDR_IN destAddr;
- memset(&destAddr, 0, sizeof(destAddr));
- destAddr.sin_family = AF_INET;
- destAddr.sin_addr.s_addr = inet_addr("223.255.255.255");
- destAddr.sin_port = 0;
- if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) {
+ if (GetBestInterface(inet_addr("223.255.255.255"), &ifbestidx) == NO_ERROR) {
DWORD dwRetVal = NO_ERROR;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 15360;
@@ -672,6 +703,13 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
+ if(ifindex == 0)
+ {
+ if(error)
+ *error = MINISSDPC_INVALID_INPUT;
+ fprintf(stderr, "Invalid multicast interface name %s\n", multicastif);
+ goto error;
+ }
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF");
@@ -683,7 +721,18 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
#endif
} else {
struct in_addr mc_if;
- mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
+#if defined(_WIN32)
+#if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ InetPtonA(AF_INET, multicastif, &mc_if);
+#else
+ mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */
+#endif
+#else
+ /* was : mc_if.s_addr = inet_addr(multicastif); */ /* ex: 192.168.x.x */
+ if (inet_pton(AF_INET, multicastif, &mc_if.s_addr) <= 0) {
+ mc_if.s_addr = INADDR_NONE;
+ }
+#endif
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
@@ -692,16 +741,11 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
}
} else {
-#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
+#ifndef _WIN32
+#ifdef HAS_IP_MREQN
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
- memset(&reqn, 0, sizeof(struct ip_mreqn));
- reqn.imr_ifindex = if_nametoindex(multicastif);
- if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
- {
- PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
- }
-#elif !defined(_WIN32)
+#endif
struct ifreq ifr;
int ifrlen = sizeof(ifr);
strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
@@ -709,12 +753,30 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
{
PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
+ goto error;
}
mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+#ifdef HAS_IP_MREQN
+ memset(&reqn, 0, sizeof(struct ip_mreqn));
+ reqn.imr_address.s_addr = mc_if.s_addr;
+ reqn.imr_ifindex = if_nametoindex(multicastif);
+ if(reqn.imr_ifindex == 0)
+ {
+ if(error)
+ *error = MINISSDPC_INVALID_INPUT;
+ fprintf(stderr, "Invalid multicast ip address / interface name %s\n", multicastif);
+ goto error;
+ }
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
+ }
+#else
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
}
+#endif
#else /* _WIN32 */
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
@@ -838,73 +900,84 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
/* Waiting for SSDP REPLY packet to M-SEARCH
* if searchalltypes is set, enter the loop only
* when the last deviceType is reached */
- if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do {
- n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
- if (n < 0) {
- /* error */
- if(error)
- *error = MINISSDPC_SOCKET_ERROR;
- goto error;
- } else if (n == 0) {
- /* no data or Time Out */
-#ifdef DEBUG
- printf("NODATA or TIMEOUT\n");
-#endif /* DEBUG */
- if (devlist && !searchalltypes) {
- /* found some devices, stop now*/
+ if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) {
+ struct timeval start = {0, 0}, current = {0, 0};
+ upnp_gettimeofday(&start);
+ do {
+ n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
+ if (n < 0) {
+ /* error */
if(error)
- *error = MINISSDPC_SUCCESS;
+ *error = MINISSDPC_SOCKET_ERROR;
goto error;
- }
- } else {
- const char * descURL=NULL;
- int urlsize=0;
- const char * st=NULL;
- int stsize=0;
- const char * usn=NULL;
- int usnsize=0;
- parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
- if(st&&descURL) {
+ } else if (n == 0) {
+ /* no data or Time Out */
#ifdef DEBUG
- printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
- stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+ printf("NODATA or TIMEOUT\n");
#endif /* DEBUG */
- for(tmp=devlist; tmp; tmp = tmp->pNext) {
- if(strncmp(tmp->descURL, descURL, urlsize) == 0 &&
- tmp->descURL[urlsize] == '\0' &&
- strncmp(tmp->st, st, stsize) == 0 &&
- tmp->st[stsize] == '\0' &&
- (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) &&
- tmp->usn[usnsize] == '\0')
- break;
- }
- /* at the exit of the loop above, tmp is null if
- * no duplicate device was found */
- if(tmp)
- continue;
- tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
- if(!tmp) {
- /* memory allocation error */
+ if (devlist && !searchalltypes) {
+ /* found some devices, stop now*/
if(error)
- *error = MINISSDPC_MEMORY_ERROR;
+ *error = MINISSDPC_SUCCESS;
goto error;
}
- tmp->pNext = devlist;
- tmp->descURL = tmp->buffer;
- tmp->st = tmp->buffer + 1 + urlsize;
- tmp->usn = tmp->st + 1 + stsize;
- memcpy(tmp->buffer, descURL, urlsize);
- tmp->buffer[urlsize] = '\0';
- memcpy(tmp->st, st, stsize);
- tmp->buffer[urlsize+1+stsize] = '\0';
- if(usn != NULL)
- memcpy(tmp->usn, usn, usnsize);
- tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
- tmp->scope_id = scope_id;
- devlist = tmp;
+ } else {
+ const char * descURL=NULL;
+ int urlsize=0;
+ const char * st=NULL;
+ int stsize=0;
+ const char * usn=NULL;
+ int usnsize=0;
+ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
+ if(st&&descURL) {
+#ifdef DEBUG
+ printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
+ stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+#endif /* DEBUG */
+ for(tmp=devlist; tmp; tmp = tmp->pNext) {
+ if(strncmp(tmp->descURL, descURL, urlsize) == 0 &&
+ tmp->descURL[urlsize] == '\0' &&
+ strncmp(tmp->st, st, stsize) == 0 &&
+ tmp->st[stsize] == '\0' &&
+ (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) &&
+ tmp->usn[usnsize] == '\0')
+ break;
+ }
+ /* at the exit of the loop above, tmp is null if
+ * no duplicate device was found */
+ if(tmp)
+ continue;
+ tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize+3);
+ if(!tmp) {
+ /* memory allocation error */
+ if(error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto error;
+ }
+ tmp->pNext = devlist;
+ tmp->descURL = tmp->buffer;
+ tmp->st = tmp->buffer + 1 + urlsize;
+ tmp->usn = tmp->st + 1 + stsize;
+ memcpy(tmp->buffer, descURL, urlsize);
+ tmp->buffer[urlsize] = '\0';
+ memcpy(tmp->st, st, stsize);
+ tmp->buffer[urlsize+1+stsize] = '\0';
+ if(usn != NULL)
+ memcpy(tmp->usn, usn, usnsize);
+ tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+ tmp->scope_id = scope_id;
+ devlist = tmp;
+ }
+ if (upnp_gettimeofday(&current) >= 0) {
+ /* exit the loop if delay is reached */
+ long interval = (current.tv_sec - start.tv_sec) * 1000;
+ interval += (current.tv_usec - start.tv_usec) / 1000;
+ if (interval > (long)delay)
+ break;
+ }
}
- }
- } while(n > 0);
+ } while(n > 0);
+ }
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
@@ -919,4 +992,3 @@ error:
closesocket(sudp);
return devlist;
}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc.c b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
index 95ab6cf56b..696af93237 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
@@ -1,9 +1,9 @@
-/* $Id: miniupnpc.c,v 1.154 2019/04/23 12:12:13 nanard Exp $ */
+/* $Id: miniupnpc.c,v 1.159 2021/03/02 23:36:32 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2019 Thomas Bernard
+ * copyright (c) 2005-2021 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
@@ -15,7 +15,7 @@
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define strdup _strdup
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
@@ -61,6 +61,7 @@
#include "minixml.h"
#include "upnpcommands.h"
#include "connecthostport.h"
+#include "addr_is_reserved.h"
/* compare the beginning of a string with a constant string */
#define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1))
@@ -73,24 +74,6 @@
#define SERVICEPREFIX "u"
#define SERVICEPREFIX2 'u'
-/* check if an ip address is a private (LAN) address
- * see https://tools.ietf.org/html/rfc1918 */
-static int is_rfc1918addr(const char * addr)
-{
- /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
- if(COMPARE(addr, "192.168."))
- return 1;
- /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
- if(COMPARE(addr, "10."))
- return 1;
- /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
- if(COMPARE(addr, "172.")) {
- if((atoi(addr + 4) | 0x0f) == 0x1f)
- return 1;
- }
- return 0;
-}
-
/* root description parsing */
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
{
@@ -337,6 +320,8 @@ upnpDiscoverDevices(const char * const deviceTypes[],
return devlist;
}
}
+#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+ (void)minissdpdsock; /* unused */
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* direct discovery if minissdpd responses are not sufficient */
@@ -643,8 +628,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* checks that status is connected AND there is a external IP address assigned */
if(is_connected &&
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
- if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
- && (0 != strcmp(extIpAddr, "0.0.0.0")))
+ if(!addr_is_reserved(extIpAddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
@@ -665,8 +649,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
#endif
if(is_connected &&
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
- if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
- && (0 != strcmp(extIpAddr, "0.0.0.0")))
+ if(!addr_is_reserved(extIpAddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
index 8ddc282bd1..3aef8ea443 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
@@ -1,9 +1,9 @@
-/* $Id: miniupnpc.h,v 1.53 2018/05/07 11:05:16 nanard Exp $ */
+/* $Id: miniupnpc.h,v 1.58 2021/03/02 23:49:52 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2021 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
@@ -20,7 +20,7 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
-#define MINIUPNPC_VERSION "2.1"
+#define MINIUPNPC_VERSION "2.2.2"
#define MINIUPNPC_API_VERSION 17
/* Source port:
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
index d4f79a7bd6..5986e58c76 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
@@ -7,7 +7,7 @@
#ifndef MINIUPNPC_SOCKETDEF_H_INCLUDED
#define MINIUPNPC_SOCKETDEF_H_INCLUDED
-#ifdef _MSC_VER
+#ifdef _WIN32
#define ISINVALID(s) (INVALID_SOCKET==(s))
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c b/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c
deleted file mode 100644
index d9341ab5bf..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c
+++ /dev/null
@@ -1,721 +0,0 @@
-/* $Id: miniupnpcmodule.c,v 1.34 2019/05/20 19:07:16 nanard Exp $*/
-/* vim: tabstop=4 shiftwidth=4 noexpandtab
- * Project : miniupnp
- * Author : Thomas BERNARD
- * website : https://miniupnp.tuxfamily.org/
- * copyright (c) 2007-2019 Thomas Bernard
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#include <Python.h>
-#define MINIUPNP_STATICLIB
-#include "structmember.h"
-#include "miniupnpc.h"
-#include "upnpcommands.h"
-#include "upnperrors.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-/* for compatibility with Python < 2.4 */
-#ifndef Py_RETURN_NONE
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#endif
-
-#ifndef Py_RETURN_TRUE
-#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
-#endif
-
-#ifndef Py_RETURN_FALSE
-#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
-#endif
-
-/* for compatibility with Python < 3.0 */
-#ifndef PyVarObject_HEAD_INIT
-#define PyVarObject_HEAD_INIT(type, size) \
- PyObject_HEAD_INIT(type) size,
-#endif
-
-#ifndef Py_TYPE
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
-#endif
-
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- struct UPNPDev * devlist;
- struct UPNPUrls urls;
- struct IGDdatas data;
- unsigned int discoverdelay; /* value passed to upnpDiscover() */
- unsigned int localport; /* value passed to upnpDiscover() */
- char lanaddr[40]; /* our ip address on the LAN */
- char * multicastif;
- char * minissdpdsocket;
-} UPnPObject;
-
-static PyMemberDef UPnP_members[] = {
- {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
- READONLY, "ip address on the LAN"
- },
- {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
- 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
- },
- {"localport", T_UINT, offsetof(UPnPObject, localport),
- 0/*READWRITE*/,
- "If localport is set to UPNP_LOCAL_PORT_SAME(1) "
- "SSDP packets will be sent from the source port "
- "1900 (same as destination port), if set to "
- "UPNP_LOCAL_PORT_ANY(0) system assign a source "
- "port, any other value will be attempted as the "
- "source port"
- },
- /* T_STRING is allways readonly :( */
- {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
- 0, "IP of the network interface to be used for multicast operations"
- },
- {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
- 0, "path of the MiniSSDPd unix socket"
- },
- {NULL}
-};
-
-
-static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
-{
- char* multicastif = NULL;
- char* minissdpdsocket = NULL;
- static char *kwlist[] = {
- "multicastif", "minissdpdsocket", "discoverdelay",
- "localport", NULL
- };
-
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
- &multicastif,
- &minissdpdsocket,
- &self->discoverdelay,
- &self->localport))
- return -1;
-
- if(self->localport>1 &&
- (self->localport>65534||self->localport<1024)) {
- PyErr_SetString(PyExc_Exception, "Invalid localport value");
- return -1;
- }
- if(multicastif)
- self->multicastif = strdup(multicastif);
- if(minissdpdsocket)
- self->minissdpdsocket = strdup(minissdpdsocket);
-
- return 0;
-}
-
-static void
-UPnPObject_dealloc(UPnPObject *self)
-{
- freeUPNPDevlist(self->devlist);
- FreeUPNPUrls(&self->urls);
- free(self->multicastif);
- free(self->minissdpdsocket);
- Py_TYPE(self)->tp_free((PyObject*)self);
-}
-
-static PyObject *
-UPnP_discover(UPnPObject *self)
-{
- struct UPNPDev * dev;
- int i;
- PyObject *res = NULL;
- if(self->devlist)
- {
- freeUPNPDevlist(self->devlist);
- self->devlist = 0;
- }
- Py_BEGIN_ALLOW_THREADS
- self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
- self->multicastif,
- self->minissdpdsocket,
- (int)self->localport,
- 0/*ip v6*/,
- 2/* TTL */,
- 0/*error */);
- Py_END_ALLOW_THREADS
- /* Py_RETURN_NONE ??? */
- for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
- i++;
- res = Py_BuildValue("i", i);
- return res;
-}
-
-static PyObject *
-UPnP_selectigd(UPnPObject *self)
-{
- int r;
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
- self->lanaddr, sizeof(self->lanaddr));
-Py_END_ALLOW_THREADS
- if(r)
- {
- return Py_BuildValue("s", self->urls.controlURL);
- }
- else
- {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_totalbytesent(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalbytereceived(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalpacketsent(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalpacketreceived(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_statusinfo(UPnPObject *self)
-{
- char status[64];
- char lastconnerror[64];
- unsigned int uptime = 0;
- int r;
- status[0] = '\0';
- lastconnerror[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
- status, &uptime, lastconnerror);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
-#else
- return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
-#endif
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_connectiontype(UPnPObject *self)
-{
- char connectionType[64];
- int r;
- connectionType[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
- self->data.first.servicetype,
- connectionType);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("s", connectionType);
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_externalipaddress(UPnPObject *self)
-{
- char externalIPAddress[40];
- int r;
- externalIPAddress[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetExternalIPAddress(self->urls.controlURL,
- self->data.first.servicetype,
- externalIPAddress);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("s", externalIPAddress);
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
- * remoteHost, leaseDuration)
- * protocol is 'UDP' or 'TCP' */
-static PyObject *
-UPnP_addportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- char inPort[6];
- unsigned short iPort;
- const char * proto;
- const char * host;
- const char * desc;
- const char * remoteHost;
- unsigned int intLeaseDuration = 0;
- char strLeaseDuration[12];
- int r;
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto,
- &host, &iPort, &desc, &remoteHost, &intLeaseDuration))
-#else
- if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto,
- &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration))
-#endif
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- sprintf(inPort, "%hu", iPort);
- sprintf(strLeaseDuration, "%u", intLeaseDuration);
- r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, inPort, host, desc, proto,
- remoteHost, strLeaseDuration);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS)
- {
- Py_RETURN_TRUE;
- }
- else
- {
- // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
- // upnperrors.c
- //Py_RETURN_FALSE;
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
- * remoteHost)
- * protocol is 'UDP' or 'TCP' */
-static PyObject *
-UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- char inPort[6];
- unsigned short iPort;
- char reservedPort[6];
- const char * proto;
- const char * host;
- const char * desc;
- const char * remoteHost;
- const char * leaseDuration = "0";
- int r;
- if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- sprintf(inPort, "%hu", iPort);
- r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, inPort, host, desc, proto,
- remoteHost, leaseDuration, reservedPort);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("i", atoi(reservedPort));
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-
-/* DeletePortMapping(extPort, proto, removeHost='')
- * proto = 'UDP', 'TCP' */
-static PyObject *
-UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- const char * proto;
- const char * remoteHost = "";
- int r;
- if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, proto, remoteHost);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- Py_RETURN_TRUE;
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* DeletePortMappingRange(extPort, proto, removeHost='')
- * proto = 'UDP', 'TCP' */
-static PyObject *
-UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
-{
- char extPortStart[6];
- unsigned short ePortStart;
- char extPortEnd[6];
- unsigned short ePortEnd;
- const char * proto;
- unsigned char manage;
- char manageStr[6];
- int r;
- if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPortStart, "%hu", ePortStart);
- sprintf(extPortEnd, "%hu", ePortEnd);
- sprintf(manageStr, "%hu", (unsigned short)manage);
- r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
- extPortStart, extPortEnd, proto, manageStr);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- Py_RETURN_TRUE;
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_getportmappingnumberofentries(UPnPObject *self)
-{
- unsigned int n = 0;
- int r;
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
- self->data.first.servicetype,
- &n);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", n);
-#else
- return Py_BuildValue("i", (int)n);
-#endif
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* GetSpecificPortMapping(ePort, proto, remoteHost='')
- * proto = 'UDP' or 'TCP' */
-static PyObject *
-UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- const char * proto;
- const char * remoteHost = "";
- char intClient[40];
- char intPort[6];
- unsigned short iPort;
- char desc[80];
- char enabled[4];
- char leaseDuration[16];
- if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
- return NULL;
- extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
- desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
- self->data.first.servicetype,
- extPort, proto, remoteHost,
- intClient, intPort,
- desc, enabled, leaseDuration);
-Py_END_ALLOW_THREADS
- if(intClient[0])
- {
- iPort = (unsigned short)atoi(intPort);
- return Py_BuildValue("(s,H,s,O,i)",
- intClient, iPort, desc,
- PyBool_FromLong(atoi(enabled)),
- atoi(leaseDuration));
- }
- else
- {
- Py_RETURN_NONE;
- }
-}
-
-/* GetGenericPortMapping(index) */
-static PyObject *
-UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
-{
- int i, r;
- char index[8];
- char intClient[40];
- char intPort[6];
- unsigned short iPort;
- char extPort[6];
- unsigned short ePort;
- char protocol[4];
- char desc[80];
- char enabled[6];
- char rHost[64];
- char duration[16]; /* lease duration */
- unsigned int dur;
- if(!PyArg_ParseTuple(args, "i", &i))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- snprintf(index, sizeof(index), "%d", i);
- rHost[0] = '\0'; enabled[0] = '\0';
- duration[0] = '\0'; desc[0] = '\0';
- extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
- r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
- self->data.first.servicetype,
- index,
- extPort, intClient, intPort,
- protocol, desc, enabled, rHost,
- duration);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS)
- {
- ePort = (unsigned short)atoi(extPort);
- iPort = (unsigned short)atoi(intPort);
- dur = (unsigned int)strtoul(duration, 0, 0);
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
- ePort, protocol, intClient, iPort,
- desc, enabled, rHost, dur);
-#else
- return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
- (int)ePort, protocol, intClient, (int)iPort,
- desc, enabled, rHost, (int)dur);
-#endif
- }
- else
- {
- Py_RETURN_NONE;
- }
-}
-
-/* miniupnpc.UPnP object Method Table */
-static PyMethodDef UPnP_methods[] = {
- {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
- "discover UPnP IGD devices on the network"
- },
- {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
- "select a valid UPnP IGD among discovered devices"
- },
- {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
- "return the total number of bytes sent by UPnP IGD"
- },
- {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
- "return the total number of bytes received by UPnP IGD"
- },
- {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
- "return the total number of packets sent by UPnP IGD"
- },
- {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
- "return the total number of packets received by UPnP IGD"
- },
- {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
- "return status and uptime"
- },
- {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
- "return IGD WAN connection type"
- },
- {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
- "return external IP address"
- },
- {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
- "add a port mapping"
- },
- {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
- "add a port mapping, IGD to select alternative if necessary"
- },
- {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
- "delete a port mapping"
- },
- {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
- "delete a range of port mappings"
- },
- {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
- "-- non standard --"
- },
- {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
- "get details about a specific port mapping entry"
- },
- {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
- "get all details about the port mapping at index"
- },
- {NULL} /* Sentinel */
-};
-
-static PyTypeObject UPnPType = {
- PyVarObject_HEAD_INIT(NULL,
- 0) /*ob_size*/
- "miniupnpc.UPnP", /*tp_name*/
- sizeof(UPnPObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)UPnPObject_dealloc,/*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "UPnP objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- UPnP_methods, /* tp_methods */
- UPnP_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)UPnP_init, /* tp_init */
- 0, /* tp_alloc */
-#ifndef _WIN32
- PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
-#else
- 0,
-#endif
-};
-
-/* module methods */
-static PyMethodDef miniupnpc_methods[] = {
- {NULL} /* Sentinel */
-};
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "miniupnpc", /* m_name */
- "miniupnpc module.", /* m_doc */
- -1, /* m_size */
- miniupnpc_methods, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear */
- NULL, /* m_free */
-};
-#endif
-
-#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-
-PyMODINIT_FUNC
-#if PY_MAJOR_VERSION >= 3
-PyInit_miniupnpc(void)
-#else
-initminiupnpc(void)
-#endif
-{
- PyObject* m;
-
-#ifdef _WIN32
- /* initialize Winsock. */
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if (nResult != 0)
- {
- /* error code could be WSASYSNOTREADY WSASYSNOTREADY
- * WSASYSNOTREADY WSASYSNOTREADY WSASYSNOTREADY */
-#if PY_MAJOR_VERSION >= 3
- return 0;
-#else
- return;
-#endif
- }
-
- UPnPType.tp_new = PyType_GenericNew;
-#endif
- if (PyType_Ready(&UPnPType) < 0)
-#if PY_MAJOR_VERSION >= 3
- return 0;
-#else
- return;
-#endif
-
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&moduledef);
-#else
- m = Py_InitModule3("miniupnpc", miniupnpc_methods,
- "miniupnpc module.");
-#endif
-
- Py_INCREF(&UPnPType);
- PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
-
-#if PY_MAJOR_VERSION >= 3
- return m;
-#endif
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
index a718cc7bbf..7b3d04074a 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
@@ -4,7 +4,7 @@
#include "core/version.h"
#define OS_STRING VERSION_NAME "/1.0"
-#define MINIUPNPC_VERSION_STRING "2.1"
+#define MINIUPNPC_VERSION_STRING "2.2.2"
#if 0
/* according to "UPnP Device Architecture 1.0" */
diff --git a/thirdparty/miniupnpc/miniupnpc/miniwget.c b/thirdparty/miniupnpc/miniupnpc/miniwget.c
index 5c135f4efd..d5b7970632 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniwget.c
+++ b/thirdparty/miniupnpc/miniupnpc/miniwget.c
@@ -1,8 +1,8 @@
-/* $Id: miniwget.c,v 1.78 2018/03/13 23:22:18 nanard Exp $ */
+/* $Id: miniwget.c,v 1.82 2020/05/29 21:14:22 nanard Exp $ */
/* Project : miniupnp
- * Website : http://miniupnp.free.fr/
+ * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -15,7 +15,7 @@
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define socklen_t int
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
@@ -176,11 +176,14 @@ getHTTPResponse(SOCKET s, int * size, int * status_code)
/* Status line
* HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
int sp;
- for(sp = 0; sp < i; sp++)
+ for(sp = 0; sp < i - 1; sp++)
if(header_buf[sp] == ' ')
{
if(*status_code < 0)
- *status_code = atoi(header_buf + sp + 1);
+ {
+ if (header_buf[sp+1] >= '1' && header_buf[sp+1] <= '9')
+ *status_code = atoi(header_buf + sp + 1);
+ }
else
{
#ifdef DEBUG
diff --git a/thirdparty/miniupnpc/miniupnpc/portlistingparse.c b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
index 18d967b877..162cf8b7ec 100644
--- a/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
+++ b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
@@ -15,7 +15,7 @@
#if defined(__HAIKU__)
/* rename our private function because Haiku already defines a atoui() function */
#define atoui atoui2
-#endif
+#endif
/* list of the elements */
static const struct {
diff --git a/thirdparty/miniupnpc/miniupnpc/receivedata.c b/thirdparty/miniupnpc/miniupnpc/receivedata.c
index 7b9cc5b778..7f187f6e56 100644
--- a/thirdparty/miniupnpc/miniupnpc/receivedata.c
+++ b/thirdparty/miniupnpc/miniupnpc/receivedata.c
@@ -1,8 +1,8 @@
-/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */
+/* $Id: receivedata.c,v 1.10 2021/03/02 23:33:07 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
- * Copyright (c) 2011-2014 Thomas Bernard
+ * Copyright (c) 2011-2021 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -92,7 +92,13 @@ receivedata(SOCKET socket,
#endif /* DEBUG */
if(scope_id)
*scope_id = src_addr6->sin6_scope_id;
+ } else {
+ if(scope_id)
+ *scope_id = 0;
}
+#else /* MINIUPNPC_GET_SRC_ADDR */
+ if(scope_id)
+ *scope_id = 0;
#endif /* MINIUPNPC_GET_SRC_ADDR */
return n;
}
diff --git a/thirdparty/miniupnpc/miniupnpc/upnpc.c b/thirdparty/miniupnpc/miniupnpc/upnpc.c
deleted file mode 100644
index cb7f18b5f6..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnpc.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/* $Id: upnpc.c,v 1.119 2018/03/13 23:34:46 nanard Exp $ */
-/* Project : miniupnp
- * Author : Thomas Bernard
- * Copyright (c) 2005-2020 Thomas Bernard
- * This software is subject to the conditions detailed in the
- * LICENCE file provided in this distribution. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#define snprintf _snprintf
-#else
-/* for IPPROTO_TCP / IPPROTO_UDP */
-#include <netinet/in.h>
-#endif
-#include <ctype.h>
-#include "miniwget.h"
-#include "miniupnpc.h"
-#include "upnpcommands.h"
-#include "portlistingparse.h"
-#include "upnperrors.h"
-#include "miniupnpcstrings.h"
-
-/* protofix() checks if protocol is "UDP" or "TCP"
- * returns NULL if not */
-const char * protofix(const char * proto)
-{
- static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
- static const char proto_udp[4] = { 'U', 'D', 'P', 0};
- int i, b;
- for(i=0, b=1; i<4; i++)
- b = b && ( (proto[i] == proto_tcp[i])
- || (proto[i] == (proto_tcp[i] | 32)) );
- if(b)
- return proto_tcp;
- for(i=0, b=1; i<4; i++)
- b = b && ( (proto[i] == proto_udp[i])
- || (proto[i] == (proto_udp[i] | 32)) );
- if(b)
- return proto_udp;
- return 0;
-}
-
-/* is_int() checks if parameter is an integer or not
- * 1 for integer
- * 0 for not an integer */
-int is_int(char const* s)
-{
- if(s == NULL)
- return 0;
- while(*s) {
- /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
- if(!isdigit(*s))
- return 0;
- s++;
- }
- return 1;
-}
-
-static void DisplayInfos(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- char externalIPAddress[40];
- char connectionType[64];
- char status[64];
- char lastconnerr[64];
- unsigned int uptime = 0;
- unsigned int brUp, brDown;
- time_t timenow, timestarted;
- int r;
- if(UPNP_GetConnectionTypeInfo(urls->controlURL,
- data->first.servicetype,
- connectionType) != UPNPCOMMAND_SUCCESS)
- printf("GetConnectionTypeInfo failed.\n");
- else
- printf("Connection Type : %s\n", connectionType);
- if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
- status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
- printf("GetStatusInfo failed.\n");
- else
- printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
- status, uptime, lastconnerr);
- if(uptime > 0) {
- timenow = time(NULL);
- timestarted = timenow - uptime;
- printf(" Time started : %s", ctime(&timestarted));
- }
- if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
- &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
- printf("GetLinkLayerMaxBitRates failed.\n");
- } else {
- printf("MaxBitRateDown : %u bps", brDown);
- if(brDown >= 1000000) {
- printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
- } else if(brDown >= 1000) {
- printf(" (%u Kbps)", brDown / 1000);
- }
- printf(" MaxBitRateUp %u bps", brUp);
- if(brUp >= 1000000) {
- printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
- } else if(brUp >= 1000) {
- printf(" (%u Kbps)", brUp / 1000);
- }
- printf("\n");
- }
- r = UPNP_GetExternalIPAddress(urls->controlURL,
- data->first.servicetype,
- externalIPAddress);
- if(r != UPNPCOMMAND_SUCCESS) {
- printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
- } else {
- printf("ExternalIPAddress = %s\n", externalIPAddress);
- }
-}
-
-static void GetConnectionStatus(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
- DisplayInfos(urls, data);
- bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
- bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
- packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
- packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
- printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
- printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
-}
-
-static void ListRedirections(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- int r;
- int i = 0;
- char index[6];
- char intClient[40];
- char intPort[6];
- char extPort[6];
- char protocol[4];
- char desc[80];
- char enabled[6];
- char rHost[64];
- char duration[16];
- /*unsigned int num=0;
- UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
- printf("PortMappingNumberOfEntries : %u\n", num);*/
- printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
- do {
- snprintf(index, 6, "%d", i);
- rHost[0] = '\0'; enabled[0] = '\0';
- duration[0] = '\0'; desc[0] = '\0';
- extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
- r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
- data->first.servicetype,
- index,
- extPort, intClient, intPort,
- protocol, desc, enabled,
- rHost, duration);
- if(r==0)
- /*
- printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
- " desc='%s' rHost='%s'\n",
- i, protocol, extPort, intClient, intPort,
- enabled, duration,
- desc, rHost);
- */
- printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
- i, protocol, extPort, intClient, intPort,
- desc, rHost, duration);
- else
- printf("GetGenericPortMappingEntry() returned %d (%s)\n",
- r, strupnperror(r));
- i++;
- } while(r==0);
-}
-
-static void NewListRedirections(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- int r;
- int i = 0;
- struct PortMappingParserData pdata;
- struct PortMapping * pm;
-
- memset(&pdata, 0, sizeof(struct PortMappingParserData));
- r = UPNP_GetListOfPortMappings(urls->controlURL,
- data->first.servicetype,
- "0",
- "65535",
- "TCP",
- "1000",
- &pdata);
- if(r == UPNPCOMMAND_SUCCESS)
- {
- printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
- for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
- {
- printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
- i, pm->protocol, pm->externalPort, pm->internalClient,
- pm->internalPort,
- pm->description, pm->remoteHost,
- (unsigned)pm->leaseTime);
- i++;
- }
- FreePortListing(&pdata);
- }
- else
- {
- printf("GetListOfPortMappings() returned %d (%s)\n",
- r, strupnperror(r));
- }
- r = UPNP_GetListOfPortMappings(urls->controlURL,
- data->first.servicetype,
- "0",
- "65535",
- "UDP",
- "1000",
- &pdata);
- if(r == UPNPCOMMAND_SUCCESS)
- {
- for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
- {
- printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
- i, pm->protocol, pm->externalPort, pm->internalClient,
- pm->internalPort,
- pm->description, pm->remoteHost,
- (unsigned)pm->leaseTime);
- i++;
- }
- FreePortListing(&pdata);
- }
- else
- {
- printf("GetListOfPortMappings() returned %d (%s)\n",
- r, strupnperror(r));
- }
-}
-
-/* Test function
- * 1 - get connection type
- * 2 - get extenal ip address
- * 3 - Add port mapping
- * 4 - get this port mapping from the IGD */
-static int SetRedirectAndTest(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * iaddr,
- const char * iport,
- const char * eport,
- const char * proto,
- const char * leaseDuration,
- const char * remoteHost,
- const char * description,
- int addAny)
-{
- char externalIPAddress[40];
- char intClient[40];
- char intPort[6];
- char reservedPort[6];
- char duration[16];
- int r;
-
- if(!iaddr || !iport || !eport || !proto)
- {
- fprintf(stderr, "Wrong arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "invalid protocol\n");
- return -1;
- }
-
- r = UPNP_GetExternalIPAddress(urls->controlURL,
- data->first.servicetype,
- externalIPAddress);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetExternalIPAddress failed.\n");
- else
- printf("ExternalIPAddress = %s\n", externalIPAddress);
-
- if (addAny) {
- r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
- eport, iport, iaddr, description,
- proto, remoteHost, leaseDuration, reservedPort);
- if(r==UPNPCOMMAND_SUCCESS)
- eport = reservedPort;
- else
- printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
- eport, iport, iaddr, r, strupnperror(r));
- } else {
- r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
- eport, iport, iaddr, description,
- proto, remoteHost, leaseDuration);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
- eport, iport, iaddr, r, strupnperror(r));
- return -2;
- }
- }
-
- r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
- data->first.servicetype,
- eport, proto, remoteHost,
- intClient, intPort, NULL/*desc*/,
- NULL/*enabled*/, duration);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
- r, strupnperror(r));
- return -2;
- } else {
- printf("InternalIP:Port = %s:%s\n", intClient, intPort);
- printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
- externalIPAddress, eport, proto, intClient, intPort, duration);
- }
- return 0;
-}
-
-static int
-RemoveRedirect(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * eport,
- const char * proto,
- const char * remoteHost)
-{
- int r;
- if(!proto || !eport)
- {
- fprintf(stderr, "invalid arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "protocol invalid\n");
- return -1;
- }
- r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("UPNP_DeletePortMapping() failed with code : %d\n", r);
- return -2;
- }else {
- printf("UPNP_DeletePortMapping() returned : %d\n", r);
- }
- return 0;
-}
-
-static int
-RemoveRedirectRange(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * ePortStart, char const * ePortEnd,
- const char * proto, const char * manage)
-{
- int r;
-
- if (!manage)
- manage = "0";
-
- if(!proto || !ePortStart || !ePortEnd)
- {
- fprintf(stderr, "invalid arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "protocol invalid\n");
- return -1;
- }
- r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r);
- return -2;
- }else {
- printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
- }
- return 0;
-}
-
-/* IGD:2, functions for service WANIPv6FirewallControl:1 */
-static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
-{
- unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
- int firewallEnabled = 0, inboundPinholeAllowed = 0;
-
- UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
- printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
- printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
-
- bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
- bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
- packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
- packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
- printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
- printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
-}
-
-/* Test function
- * 1 - Add pinhole
- * 2 - Check if pinhole is working from the IGD side */
-static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * remoteaddr, const char * eport,
- const char * intaddr, const char * iport,
- const char * proto, const char * lease_time)
-{
- char uniqueID[8];
- /*int isWorking = 0;*/
- int r;
- char proto_tmp[8];
-
- if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
- if(atoi(proto) == 0)
- {
- const char * protocol;
- protocol = protofix(proto);
- if(protocol && (strcmp("TCP", protocol) == 0))
- {
- snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
- proto = proto_tmp;
- }
- else if(protocol && (strcmp("UDP", protocol) == 0))
- {
- snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
- proto = proto_tmp;
- }
- else
- {
- fprintf(stderr, "invalid protocol\n");
- return;
- }
- }
- r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
- remoteaddr, eport, intaddr, iport, r, strupnperror(r));
- else
- {
- printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
- remoteaddr, eport, intaddr, iport, uniqueID);
- /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
- }
-}
-
-/* Test function
- * 1 - Check if pinhole is working from the IGD side
- * 2 - Update pinhole */
-static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * uniqueID, const char * lease_time)
-{
- int isWorking = 0;
- int r;
-
- if(!uniqueID || !lease_time)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
- r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- if(isWorking || r==709)
- {
- r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
- printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
- }
-}
-
-/* Test function
- * Get pinhole timeout
- */
-static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * remoteaddr, const char * eport,
- const char * intaddr, const char * iport,
- const char * proto)
-{
- int timeout = 0;
- int r;
-
- if(!intaddr || !remoteaddr || !iport || !eport || !proto)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
-
- r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
- intaddr, iport, remoteaddr, eport, r, strupnperror(r));
- else
- printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
-}
-
-static void
-GetPinholePackets(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r, pinholePackets = 0;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
- else
- printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
-}
-
-static void
-CheckPinhole(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r, isWorking = 0;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- else
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
-}
-
-static void
-RemovePinhole(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
- printf("UPNP_DeletePinhole() returned : %d\n", r);
-}
-
-
-/* sample upnp client program */
-int main(int argc, char ** argv)
-{
- char command = 0;
- char ** commandargv = 0;
- int commandargc = 0;
- struct UPNPDev * devlist = 0;
- char lanaddr[64] = "unset"; /* my ip address on the LAN */
- int i;
- const char * rootdescurl = 0;
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- int localport = UPNP_LOCAL_PORT_ANY;
- int retcode = 0;
- int error = 0;
- int ipv6 = 0;
- unsigned char ttl = 2; /* defaulting to 2 */
- const char * description = 0;
-
-#ifdef _WIN32
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if(nResult != NO_ERROR)
- {
- fprintf(stderr, "WSAStartup() failed.\n");
- return -1;
- }
-#endif
- printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
- printf(" (c) 2005-2020 Thomas Bernard.\n");
- printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
- "for more information.\n");
- /* command line processing */
- for(i=1; i<argc; i++)
- {
- if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
- {
- command = 0;
- break;
- }
- if(argv[i][0] == '-')
- {
- if(argv[i][1] == 'u')
- rootdescurl = argv[++i];
- else if(argv[i][1] == 'm')
- {
- multicastif = argv[++i];
- minissdpdpath = ""; /* Disable usage of minissdpd */
- }
- else if(argv[i][1] == 'z')
- {
- char junk;
- if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
- localport<0 || localport>65535 ||
- (localport >1 && localport < 1024))
- {
- fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
- localport = UPNP_LOCAL_PORT_ANY;
- break;
- }
- }
- else if(argv[i][1] == 'p')
- minissdpdpath = argv[++i];
- else if(argv[i][1] == '6')
- ipv6 = 1;
- else if(argv[i][1] == 'e')
- description = argv[++i];
- else if(argv[i][1] == 't')
- ttl = (unsigned char)atoi(argv[++i]);
- else
- {
- command = argv[i][1];
- i++;
- commandargv = argv + i;
- commandargc = argc - i;
- break;
- }
- }
- else
- {
- fprintf(stderr, "option '%s' invalid\n", argv[i]);
- }
- }
-
- if(!command
- || (command == 'a' && commandargc<4)
- || (command == 'd' && argc<2)
- || (command == 'r' && argc<2)
- || (command == 'A' && commandargc<6)
- || (command == 'U' && commandargc<2)
- || (command == 'D' && commandargc<1))
- {
- fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration] [remote host]\n\t\tAdd port redirection\n", argv[0]);
- fprintf(stderr, " \t%s [options] -d external_port protocol [remote host]\n\t\tDelete port redirection\n", argv[0]);
- fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
- fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
- fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration] [remote host]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
- fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
- fprintf(stderr, "\nprotocol is UDP or TCP\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -e description : set description for port mapping.\n");
- fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
- fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
- fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
- fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
- fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
- fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
- return 1;
- }
-
- if( rootdescurl
- || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
- localport, ipv6, ttl, &error)))
- {
- struct UPNPDev * device;
- struct UPNPUrls urls;
- struct IGDdatas data;
- if(devlist)
- {
- printf("List of UPNP devices found on the network :\n");
- for(device = devlist; device; device = device->pNext)
- {
- printf(" desc: %s\n st: %s\n\n",
- device->descURL, device->st);
- }
- }
- else if(!rootdescurl)
- {
- printf("upnpDiscover() error code=%d\n", error);
- }
- i = 1;
- if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
- || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
- {
- switch(i) {
- case 1:
- printf("Found valid IGD : %s\n", urls.controlURL);
- break;
- case 2:
- printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- break;
- case 3:
- printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- break;
- default:
- printf("Found device (igd ?) : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- }
- printf("Local LAN ip address : %s\n", lanaddr);
- #if 0
- printf("getting \"%s\"\n", urls.ipcondescURL);
- descXML = miniwget(urls.ipcondescURL, &descXMLsize);
- if(descXML)
- {
- /*fwrite(descXML, 1, descXMLsize, stdout);*/
- free(descXML); descXML = NULL;
- }
- #endif
-
- switch(command)
- {
- case 'l':
- DisplayInfos(&urls, &data);
- ListRedirections(&urls, &data);
- break;
- case 'L':
- NewListRedirections(&urls, &data);
- break;
- case 'a':
- if (SetRedirectAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- (commandargc > 4)&is_int(commandargv[4])?commandargv[4]:"0",
- (commandargc > 4)&!is_int(commandargv[4])?commandargv[4]:(commandargc > 5)?commandargv[5]:NULL,
- description, 0) < 0)
- retcode = 2;
- break;
- case 'd':
- if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
- commandargc > 2 ? commandargv[2] : NULL) < 0)
- retcode = 2;
- break;
- case 'n': /* aNy */
- if (SetRedirectAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- (commandargc > 4)&is_int(commandargv[4])?commandargv[4]:"0",
- (commandargc > 4)&!is_int(commandargv[4])?commandargv[4]:(commandargc > 5)?commandargv[5]:NULL,
- description, 1) < 0)
- retcode = 2;
- break;
- case 'N':
- if (commandargc < 3)
- fprintf(stderr, "too few arguments\n");
-
- if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
- commandargc > 3 ? commandargv[3] : NULL) < 0)
- retcode = 2;
- break;
- case 's':
- GetConnectionStatus(&urls, &data);
- break;
- case 'r':
- i = 0;
- while(i<commandargc)
- {
- if(!is_int(commandargv[i])) {
- /* 1st parameter not an integer : error */
- fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
- retcode = 1;
- break;
- } else if(is_int(commandargv[i+1])){
- /* 2nd parameter is an integer : <port> <external_port> <protocol> */
- if (SetRedirectAndTest(&urls, &data,
- lanaddr, commandargv[i],
- commandargv[i+1], commandargv[i+2], "0", NULL,
- description, 0) < 0)
- retcode = 2;
- i+=3; /* 3 parameters parsed */
- } else {
- /* 2nd parameter not an integer : <port> <protocol> */
- if (SetRedirectAndTest(&urls, &data,
- lanaddr, commandargv[i],
- commandargv[i], commandargv[i+1], "0", NULL,
- description, 0) < 0)
- retcode = 2;
- i+=2; /* 2 parameters parsed */
- }
- }
- break;
- case 'A':
- SetPinholeAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- commandargv[4], commandargv[5]);
- break;
- case 'U':
- GetPinholeAndUpdate(&urls, &data,
- commandargv[0], commandargv[1]);
- break;
- case 'C':
- for(i=0; i<commandargc; i++)
- {
- CheckPinhole(&urls, &data, commandargv[i]);
- }
- break;
- case 'K':
- for(i=0; i<commandargc; i++)
- {
- GetPinholePackets(&urls, &data, commandargv[i]);
- }
- break;
- case 'D':
- for(i=0; i<commandargc; i++)
- {
- RemovePinhole(&urls, &data, commandargv[i]);
- }
- break;
- case 'S':
- GetFirewallStatus(&urls, &data);
- break;
- case 'G':
- GetPinholeOutboundTimeout(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- commandargv[4]);
- break;
- case 'P':
- printf("Presentation URL found:\n");
- printf(" %s\n", data.presentationurl);
- break;
- default:
- fprintf(stderr, "Unknown switch -%c\n", command);
- retcode = 1;
- }
-
- FreeUPNPUrls(&urls);
- }
- else
- {
- fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
- retcode = 1;
- }
- freeUPNPDevlist(devlist); devlist = 0;
- }
- else
- {
- fprintf(stderr, "No IGD UPnP Device found on the network !\n");
- retcode = 1;
- }
-#ifdef _WIN32
- nResult = WSACleanup();
- if(nResult != NO_ERROR) {
- fprintf(stderr, "WSACleanup() failed.\n");
- }
-#endif /* _WIN32 */
- return retcode;
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/upnpdev.h b/thirdparty/miniupnpc/miniupnpc/upnpdev.h
index f4ae174426..9b2cb431ba 100644
--- a/thirdparty/miniupnpc/miniupnpc/upnpdev.h
+++ b/thirdparty/miniupnpc/miniupnpc/upnpdev.h
@@ -1,8 +1,8 @@
-/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* $Id: upnpdev.h,v 1.3 2020/05/29 15:57:42 nanard Exp $ */
/* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2018 Thomas Bernard
+ * copyright (c) 2005-2020 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
@@ -20,7 +20,15 @@ struct UPNPDev {
char * st;
char * usn;
unsigned int scope_id;
- char buffer[3];
+#if defined(__STDC_VERSION) && __STDC_VERSION__ >= 199901L
+ /* C99 flexible array member */
+ char buffer[];
+#elif defined(__GNUC__)
+ char buffer[0];
+#else
+ /* Fallback to a hack */
+ char buffer[1];
+#endif
};
/* freeUPNPDevlist()
diff --git a/thirdparty/miniupnpc/miniupnpc/upnperrors.c b/thirdparty/miniupnpc/miniupnpc/upnperrors.c
deleted file mode 100644
index 4496e8622c..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnperrors.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id: upnperrors.c,v 1.10 2019/08/24 08:49:53 nanard Exp $ */
-/* vim: tabstop=4 shiftwidth=4 noexpandtab
- * Project : miniupnp
- * Author : Thomas BERNARD
- * copyright (c) 2007-2019 Thomas Bernard
- * All Right reserved.
- * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#include <string.h>
-#include "upnperrors.h"
-#include "upnpcommands.h"
-#include "miniupnpc.h"
-
-const char * strupnperror(int err)
-{
- const char * s = NULL;
- switch(err) {
- case UPNPCOMMAND_SUCCESS:
- s = "Success";
- break;
- case UPNPCOMMAND_UNKNOWN_ERROR:
- s = "Miniupnpc Unknown Error";
- break;
- case UPNPCOMMAND_INVALID_ARGS:
- s = "Miniupnpc Invalid Arguments";
- break;
- case UPNPCOMMAND_INVALID_RESPONSE:
- s = "Miniupnpc Invalid response";
- break;
- case UPNPCOMMAND_HTTP_ERROR:
- s = "Miniupnpc HTTP error";
- break;
- case UPNPDISCOVER_SOCKET_ERROR:
- s = "Miniupnpc Socket error";
- break;
- case UPNPDISCOVER_MEMORY_ERROR:
- case UPNPCOMMAND_MEM_ALLOC_ERROR:
- s = "Miniupnpc Memory allocation error";
- break;
- case 401:
- s = "Invalid Action";
- break;
- case 402:
- s = "Invalid Args";
- break;
- case 501:
- s = "Action Failed";
- break;
- case 606:
- s = "Action not authorized";
- break;
- case 701:
- s = "PinholeSpaceExhausted";
- break;
- case 702:
- s = "FirewallDisabled";
- break;
- case 703:
- s = "InboundPinholeNotAllowed";
- break;
- case 704:
- s = "NoSuchEntry";
- break;
- case 705:
- s = "ProtocolNotSupported";
- break;
- case 706:
- s = "InternalPortWildcardingNotAllowed";
- break;
- case 707:
- s = "ProtocolWildcardingNotAllowed";
- break;
- case 708:
- s = "InvalidLayer2Address";
- break;
- case 709:
- s = "NoPacketSent";
- break;
- case 713:
- s = "SpecifiedArrayIndexInvalid";
- break;
- case 714:
- s = "NoSuchEntryInArray";
- break;
- case 715:
- s = "WildCardNotPermittedInSrcIP";
- break;
- case 716:
- s = "WildCardNotPermittedInExtPort";
- break;
- case 718:
- s = "ConflictInMappingEntry";
- break;
- case 724:
- s = "SamePortValuesRequired";
- break;
- case 725:
- s = "OnlyPermanentLeasesSupported";
- break;
- case 726:
- s = "RemoteHostOnlySupportsWildcard";
- break;
- case 727:
- s = "ExternalPortOnlySupportsWildcard";
- break;
- default:
- s = "UnknownError";
- break;
- }
- return s;
-}
diff --git a/thirdparty/miniupnpc/miniupnpc/upnperrors.h b/thirdparty/miniupnpc/miniupnpc/upnperrors.h
deleted file mode 100644
index 8499d9a1c9..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnperrors.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
-/* (c) 2007-2015 Thomas Bernard
- * All rights reserved.
- * MiniUPnP Project.
- * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#ifndef UPNPERRORS_H_INCLUDED
-#define UPNPERRORS_H_INCLUDED
-
-#include "miniupnpc_declspec.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* strupnperror()
- * Return a string description of the UPnP error code
- * or NULL for undefinded errors */
-MINIUPNP_LIBSPEC const char * strupnperror(int err);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h b/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h
new file mode 100644
index 0000000000..1fc284ecff
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h
@@ -0,0 +1,71 @@
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * MiniUPnP project
+ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * (c) 2020 Pali Rohár
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#ifndef WIN32_SNPRINTF_H
+#define WIN32_SNPRINTF_H
+
+#ifdef _WIN32
+
+#include <stdio.h>
+
+/* snprintf is supported by:
+ * - Visual Studio 2015 or new
+ * - mingw32 with iso c ext
+ * - mingw-w64 with ansi stdio
+ * - mingw-w64 6.0.0 or new with ucrt
+ * - mingw-w64 8.0.0 or new with iso c ext
+ */
+#if ( \
+ (defined(_MSC_VER) && _MSC_VER < 1900) /* Visual Studio older than 2015 */ || \
+ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__NO_ISOCEXT)) /* mingw32 without iso c ext */ || \
+ (defined(__MINGW64_VERSION_MAJOR) && /* mingw-w64 not ... */ !( \
+ (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0)) /* ... with ansi stdio */ || \
+ (__MINGW64_VERSION_MAJOR >= 6 && defined(_UCRT)) /* ... at least 6.0.0 with ucrt */ || \
+ (__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT)) /* ... at least 8.0.0 with iso c ext */ || \
+ 0) || \
+0)
+
+/* _scprintf is supported by:
+ * - Visual Studio 2002 or new
+ * - msvcr70.dll or new
+ * - msvcrt.dll on Windows XP or new
+ */
+#if ( \
+ (defined(_MSC_VER) && _MSC_VER < 1300) /* Visual Studio older than 2002 */ || \
+ (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x700) /* msvcrt older than 7.0 */ || \
+0)
+#define CHECK_SCPRINTF 0
+#define IF_SCPRINTF(expr) 0
+#define ELSE_SCPRINTF(expr) expr
+#else
+#define CHECK_SCPRINTF 1
+#define IF_SCPRINTF(expr) expr
+#define ELSE_SCPRINTF(expr) 0
+#endif
+
+/* Emulation of snprintf for win32 */
+#define snprintf(buf, size, fmt, ...) ( \
+ (((size) != 0 && (buf) != NULL) ? ( /* _snprintf does not work with NULL buffer */ \
+ _snprintf((buf), (size), (fmt), __VA_ARGS__), /* _snprintf returns -1 on overflow, so ignore its value */ \
+ (((char *)buf)[(size_t)(size)-1] = 0), /* _snprintf does not fill nul byte on overflow */ \
+ 0) : 0), \
+ (CHECK_SCPRINTF ? IF_SCPRINTF( \
+ _scprintf((fmt), __VA_ARGS__) /* calculate return value for snprintf via _scprintf */ \
+ ) : ELSE_SCPRINTF( \
+ ((size) != 0 && (buf) != NULL) ? \
+ strlen((buf)) /* return just length of buffer */ \
+ : \
+ 1 /* no buffer, impossible to calculate, return just non-zero number */ \
+ ) \
+ ) \
+)
+
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* WIN32_SNPRINTF_H */
diff --git a/thirdparty/miniupnpc/windows_fix.diff b/thirdparty/miniupnpc/windows_fix.diff
deleted file mode 100644
index 460b596888..0000000000
--- a/thirdparty/miniupnpc/windows_fix.diff
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-index 29f8110155..ea9af02e1f 100644
---- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-+++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-@@ -683,11 +683,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
- #endif
- } else {
- struct in_addr mc_if;
--#if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
-- InetPtonA(AF_INET, multicastif, &mc_if);
--#else
- mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
--#endif
- if(mc_if.s_addr != INADDR_NONE)
- {
- ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;